LeetCode hot 100(C++版本)(上)

LeetCode hot 100(C++版本)

哈希

第一题:两数之和

题干 :给定一个整数数组 nums和一个整数目标值 target,请你在该数组中找出和为目标值 target的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。你可以按任意顺序返回答案。

示例

  • 示例 1:输入:nums = [2,7,11,15]target = 9;输出:[0,1](解释:nums[0] + nums[1] == 9)。
  • 示例 2:输入:nums = [3,2,4]target = 6;输出:[1,2]
  • 示例 3:输入:nums = [3,3]target = 6;输出:[0,1]
C++ 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> numMap;//存储{数组:下标}
        for(int i=0;i<nums.size();i++)
        {
            int complement=target-nums[i];
            if(numMap.find(complement)!=numMap.end())
            {
                return {numMap[complement],i};
            }
            numMap[nums[i]]=i;//插入/更新操作,将数值​ nums[i]作为键,下标​ i作为值,存入哈希表
        }
        return {};//为了保证有返回值,不会执行
    }
};

第二题:最长连续序列

题干 :给定一个未排序的整数数组 nums,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。请你设计并实现时间复杂度为 O(n)的算法解决此问题。

示例

  • 示例 1:输入:nums = [100,4,200,1,3,2];输出:4(解释:最长连续序列是 [1,2,3,4],长度为 4)。
  • 示例 2:输入:nums = [0,3,7,2,5,8,4,6,0,1];输出:9
  • 示例 3:输入:nums = [1,0,1,2];输出:3
C++ 复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> numSet(nums.begin(),nums.end());
        int maxLength=0;
        for(int num:numSet)
        {
            // 只有当前数字是序列起点时才处理
            if(numSet.find(num-1)==numSet.end())
            {
                int currentNum=num;
                int currentLength=1;
                // 向后延伸连续序列
                while(numSet.find(currentNum+1)!=numSet.end())
                {
                    currentNum++;
                    currentLength++;
                }
                maxLength=max(maxLength,currentLength);
            }
        }
        return maxLength;
    }
};

双指针

第三题: 移动零

题干 :给定数组 nums,将所有 0移到数组末尾,保持非零元素相对顺序,原地操作(不复制数组)。

示例

  • 输入:nums = [0,1,0,3,12];输出:[1,3,12,0,0]

  • 输入:nums = [0];输出:[0]

    C++ 复制代码
    class Solution {
    public:
        void moveZeroes(vector<int>& nums) {
            for(int cur=0,dest=-1;cur<nums.size();cur++)
                if(nums[cur])
                    swap(nums[++dest],nums[cur]);
        }
    };

第四题:盛最多水的容器

题干 :给定长度为 n的整数数组 height(表示 n条垂线的高度),选两条线与 x轴构成容器,求最大容水量(不能倾斜)。

示例

  • 输入:height = [1,8,6,2,5,4,8,3,7];输出:49(两线高度 87,宽度 7,面积 7×7=49)。
  • 输入:height = [1,1];输出:1(两线高度 1,宽度 1,面积 1×1=1)。
C++ 复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
        int left=0,right=height.size()-1,ret=0;
        while(left<right)
        {
            int v=min(height[left],height[right])*(right-left);
            ret=max(ret,v);
            if(height[left]<height[right])left++;
            else right--;
        }
        return ret;
    }
};

第五题: 三数之和

题干 :给定整数数组 nums,找出所有和为 0且不重复的三元组 [nums[i], nums[j], nums[k]](满足 i≠j≠k),返回所有符合条件的三元组。

示例

  • 输入:nums = [-1,0,1,2,-1,-4];输出:[[-1,-1,2], [-1,0,1]]
  • 输入:nums = [0,1,1];输出:[](无和为 0的三元组)。
  • 输入:nums = [0,0,0];输出:[[0,0,0]]
C++ 复制代码
class Solution
 {
 public:
 vector<vector<int>> threeSum(vector<int>& nums) 
 {
    vector<vector<int>> ret;

    // 1. 排序
    sort(nums.begin(), nums.end());

    // 2. 利⽤双指针解决问题
    int n = nums.size();
    for(int i = 0; i < n; ) // 固定数 a
    {
        if(nums[i] > 0) break; // ⼩优化
        int left = i + 1, right = n - 1, target = -nums[i];
    while(left < right)
    {
        int sum = nums[left] + nums[right];
        if(sum > target) right--;
        else if(sum < target) left++;
        else
        {
            ret.push_back({nums[i], nums[left], nums[right]});
            left++, right--;
            // 去重操作 left 和 right
            while(left < right && nums[left] == nums[left - 1]) left++;
            while(left < right && nums[right] == nums[right + 1]) 
            right--;
        }
    }
    // 去重 i 
    i++;
    while(i < n && nums[i] == nums[i - 1]) i++;
    }
     return ret;
}
};

滑动窗口

第六题:无重复字符的最长子串

题干 :给定字符串 s,找出其中不含有重复字符的最长子串的长度。

示例

  • 输入:s = "abcabcbb";输出:3(最长子串如 "abc""bca""cab")。
  • 输入:s = "bbbbb";输出:1(最长子串为 "b")。
  • 输入:s = "pwwkew";输出:3(最长子串为 "wke")。
C++ 复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ret=0;
        int n=s.size();
        for(int i=0;i<n;i++)
        {
            int hash[128]={0};
            for(int j=i;j<n;j++)
            {
                hash[s[j]]++;
                if(hash[s[j]]>1)
                {
                    break;
                }
                ret=max(ret,j-i+1);
            }
        }
        return ret;
    }
};

第七题: 找到字符串中所有字母异位词

题干 :给定字符串 sp,找到 s中所有 p的字母异位词的子串,返回这些子串的起始索引(不考虑输出顺序)。

示例

  • 输入:s = "cbaebabacd", p = "abc";输出:[0,6](子串 "cba""bac""abc"的异位词)。
  • 输入:s = "abab", p = "ab";输出:[0,1,2](子串 "ab""ba""ab""ab"的异位词)。
C++ 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> res;
        int n=s.size(),m=p.size();
        if(n<m) return res;
        vector<int> pCount(26,0),winCount(26,0);
        // 统计 p 的字符频次
        for(char c:p)
        {
            pCount[c-'a']++;
        }
        // 初始化第一个窗口
        for(int i=0;i<m;i++)
        {
            winCount[s[i]-'a']++;
        }
        // 比较第一个窗口
        if(pCount==winCount)
        {
            res.push_back(0);
        }
        // 滑动窗口
        for(int i=m;i<n;i++)
        {
            // 加入新字符
            winCount[s[i]-'a']++;
            // 移除旧字符
            winCount[s[i-m]-'a']--;
            // 检查是否匹配
            if(pCount==winCount)
            {
                res.push_back(i-m+1);
            }
        }
        return res;
    }
};

子串

第八题:和为 K 的子数组

题干 :给你一个整数数组 nums和一个整数 k,统计并返回该数组中和为 k的子数组的个数(子数组是数组中元素的连续非空序列)。

示例

  • 示例 1:输入:nums = [1,1,1], k = 2;输出:2(子数组 [1,1](前两个元素)、[1,1](后两个元素)的和为 2)。
  • 示例 2:输入:nums = [1,2,3], k = 3;输出:2(子数组 [1,2][3]的和为 3)。
C++ 复制代码
class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
      unordered_map<int,int> prefixCount;
      prefixCount[0] =1;// 初始状态:前缀和为0出现1次
      int sum=0,count=0;
      for(int num:nums)
      {
        sum+=num;//当前前缀和
        // 如果之前出现过 prefixSum = sum - k,说明存在子数组和为k
        if (prefixCount.find(sum - k) != prefixCount.end()) {
                count += prefixCount[sum - k];
        }
            // 更新当前前缀和的出现次数
            prefixCount[sum]++;
      }
      return count;
    }
};

普通数组

第九题:最大子数组和

题干 :给定整数数组 nums,找出一个连续子数组(至少包含一个元素),使其和最大,返回这个最大和。

示例

  • 输入:nums = [-2,1,-3,4,-1,2,1,-5,4];输出:6(最大和子数组为 [4,-1,2,1])。
  • 输入:nums = [1];输出:1(仅一个元素,和为自身)。
  • 输入:nums = [5,4,-1,7,8];输出:23(最大和子数组为 [5,4,-1,7,8])。
C++ 复制代码
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int current_sum = nums[0];
        int max_sum = nums[0];
        
        for (int i = 1; i < nums.size(); i++) {
            // 如果 current_sum 大于 0,保留并累加;否则抛弃,从当前元素重新开始
            current_sum = max(nums[i], current_sum + nums[i]);
            // 更新全局最大值
            max_sum = max(max_sum, current_sum);
        }
        
        return max_sum;
    }
};

第十题: 合并区间

题干 :给定若干区间的集合 intervals(每个区间为 [start_i, end_i]),合并所有重叠的区间,返回一个不重叠且恰好覆盖所有输入区间的新区间数组。

示例

  • 输入:intervals = [[1,3],[2,6],[8,10],[15,18]];输出:[[1,6],[8,10],[15,18]](区间 [1,3][2,6]重叠,合并为 [1,6])。
  • 输入:intervals = [[1,4],[4,5]];输出:[[1,5]](区间 [1,4][4,5]可视为重叠,合并为 [1,5])。
  • 输入:intervals = [[4,7],[1,4]];输出:[[1,7]](区间 [4,7][1,4]可视为重叠,合并为 [1,7])。
C++ 复制代码
class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if (intervals.empty()) return {};
        
        // 1. 按区间起点排序
        sort(intervals.begin(), intervals.end());
        
        vector<vector<int>> res;
        res.push_back(intervals[0]); // 第一个区间直接加入
        
        for (int i = 1; i < intervals.size(); i++) {
            // 当前区间的起点 <= 上一个区间的终点 → 有重叠
            if (intervals[i][0] <= res.back()[1]) {
                // 合并:更新上一个区间的终点为较大值
                res.back()[1] = max(res.back()[1], intervals[i][1]);
            } else {
                // 无重叠,直接加入
                res.push_back(intervals[i]);
            }
        }
        
        return res;
    }
};  

第十一题: 轮转数组

题干 :给定整数数组 nums,将数组中的元素向右轮转 k个位置k为非负数),需原地修改数组(或满足空间复杂度要求)。

示例

  • 输入:nums = [1,2,3,4,5,6,7], k = 3;输出:[5,6,7,1,2,3,4](向右轮转 3 步后的结果)。
  • 输入:nums = [-1,-100,3,99], k = 2;输出:[3,99,-1,-100](向右轮转 2 步后的结果)。
C++ 复制代码
class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        if (n == 0) return;
        k = k % n;  // 防止 k 大于 n
        if (k == 0) return;

        // 1. 整体反转
        reverse(nums.begin(), nums.end());

        // 2. 反转前 k 个
        reverse(nums.begin(), nums.begin() + k);

        // 3. 反转剩余 n-k 个
        reverse(nums.begin() + k, nums.end());
    }
};

第十二题: 除了自身以外数组的乘积

题干 :给定整数数组 nums,返回数组 answer,其中 answer[i]等于 numsnums[i]之外其余所有元素的乘积。要求:不使用除法,时间复杂度 O(n),且任意元素的前缀/后缀乘积在 32 位整数范围内。

示例

  • 输入:nums = [1,2,3,4];输出:[24,12,8,6]answer[0]=2×3×4=24answer[1]=1×3×4=12,依此类推)。
  • 输入:nums = [-1,1,0,-3,3];输出:[0,0,9,0,0]answer[0]=1×0×(-3)×3=0answer[2]=(-1)×1×(-3)×3=9,依此类推)。
C++ 复制代码
class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int> answer(n);

        // 1. 计算前缀积:answer[i] = nums[0] * nums[1] * ... * nums[i-1]
        answer[0] = 1;  // 第一个元素左边没有数,乘积为1
        for (int i = 1; i < n; i++) {
            answer[i] = answer[i - 1] * nums[i - 1];
        }

        // 2. 计算后缀积并乘入 answer:从右往左,用变量 rightProduct 记录右边乘积
        int rightProduct = 1;
        for (int i = n - 1; i >= 0; i--) {
            answer[i] *= rightProduct;
            rightProduct *= nums[i];
        }

        return answer;
    }
};

矩阵

第十三题:矩阵置零

题干 :给定一个 m x n的矩阵,若某个元素为 0,则将其所在的行和列的所有元素 都设为 0。要求使用原地算法(直接修改输入的矩阵,不使用额外矩阵)。

示例

  • 输入:matrix = [[1,1,1],[1,0,1],[1,1,1]];输出:[[1,0,1],[0,0,0],[1,0,1]](中间元素为 0,其所在行、列均置 0)。
  • 输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]];输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]](第一列和第四列的元素因含 0被置 0,第一行和第四行也因含 0被置 0)。
C++ 复制代码
class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m=matrix.size();
        int n=matrix[0].size();
        vector<int> row(m),col(n);
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(!matrix[i][j])
                {
                    row[i]=col[j]=true;
                }
            }
        }
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(row[i]||col[j])
                {
                    matrix[i][j]=0;
                }
            }
        }
    }
};

第十四题:螺旋矩阵

题干 :给定一个 mn列的矩阵 matrix,按照顺时针螺旋顺序返回矩阵中的所有元素。

示例

  • 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]];输出:[1,2,3,6,9,8,7,4,5](按顺时针螺旋遍历:右→下→左→上→右...)。
  • 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]];输出:[1,2,3,4,8,12,11,10,9,5,6,7](螺旋遍历所有元素)。
c++ 复制代码
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (matrix.empty() || matrix[0].empty()) return {};
        
        int m = matrix.size(), n = matrix[0].size();
        int top = 0, bottom = m - 1, left = 0, right = n - 1;
        vector<int> result;
        
        while (top <= bottom && left <= right) {
            // 1. 左 → 右
            for (int j = left; j <= right; j++) {
                result.push_back(matrix[top][j]);
            }
            top++;
            
            // 2. 上 → 下
            for (int i = top; i <= bottom; i++) {
                result.push_back(matrix[i][right]);
            }
            right--;
            
            // 3. 右 → 左(需判断是否还有行)
            if (top <= bottom) {
                for (int j = right; j >= left; j--) {
                    result.push_back(matrix[bottom][j]);
                }
                bottom--;
            }
            
            // 4. 下 → 上(需判断是否还有列)
            if (left <= right) {
                for (int i = bottom; i >= top; i--) {
                    result.push_back(matrix[i][left]);
                }
                left++;
            }
        }
        
        return result;
    }
};

第十五题: 旋转图像

题干 :给定一个 n x n的二维矩阵(表示图像),将图像顺时针旋转 90 度 。要求原地旋转(直接修改输入的矩阵,不使用额外矩阵)。

示例

  • 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]];输出:[[7,4,1],[8,5,2],[9,6,3]](顺时针旋转 90 度后的结果)。
  • 输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]];输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]](顺时针旋转 90 度后的结果)。
C++ 复制代码
class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n=matrix.size();
        // Step 1: 转置矩阵(沿主对角线)
        for(int i=0;i<n;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                swap(matrix[i][j],matrix[j][i]);
            }
        }
        // Step 2: 反转每一行
        for(int i=0;i<n;i++)
        {
            reverse(matrix[i].begin(),matrix[i].end());
        }
    }
};

第十六题: 搜索二维矩阵 II

题干 :编写一个高效的算法,搜索 m x n矩阵 matrix中的一个目标值 target。矩阵特性:

  • 每行的元素从左到右升序排列

  • 每列的元素从上到下升序排列

    示例

  • 输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5;输出:true(目标值 5存在于矩阵中)。

  • 输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20;输出:false(目标值 20不存在于矩阵中)。

C++ 复制代码
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.empty()||matrix[0].empty())
        {
            return false;
        }
        int m=matrix.size(),n=matrix[0].size();
        int row=0,col=n-1;//从右上角开始
        while(row<m&&col>=0)
        {
            if(matrix[row][col]==target)
            {
                return true;
            }
            else if(matrix[row][col]>target)
            {
                col--;//向左
            }
            else
            {
                row++;//向下移动
            }
        }
        return false;
    }
};

链表

第十七题: 相交链表

题干 :给定两个单链表的头节点 headAheadB,找到并返回它们的相交起始节点 (若无相交返回 null)。保证链表无环。

核心 :双指针法(A走完走 BB走完走 A,相遇时即为相交点,或都走到 null)。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if (!headA || !headB) return nullptr;

        ListNode *pA = headA, *pB = headB;

        while (pA != pB) {
            pA = pA ? pA->next : headB;
            pB = pB ? pB->next : headA;
        }

        return pA;
    }
};

第十八题:反转链表

题干 :给定单链表头节点 head反转链表并返回新头节点。

核心 :迭代法(三指针 prev, curr, next)或递归法(从后往前反转)。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;   // 指向前一个节点
        ListNode* curr = head;      // 当前节点
        
        while (curr != nullptr) {
            ListNode* nextTemp = curr->next;  // 临时保存下一个节点
            curr->next = prev;                // 反转指针
            prev = curr;                      // 移动 prev
            curr = nextTemp;                  // 移动 curr
        }

        return prev;  // prev 现在是新链表的头
    }
};

第十九题:回文链表

题干 :判断单链表是否为回文链表(正读和反读相同)。

核心:快慢指针找中点,反转后半部分,比较前半和后半是否一致。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if (!head || !head->next) return true;

        // 1. 快慢指针找中点
        ListNode *slow = head, *fast = head;
        while (fast->next && fast->next->next) {
            slow = slow->next;
            fast = fast->next->next;
        }

        // 2. 反转后半部分(从 slow->next 开始)
        ListNode *secondHalf = reverseList(slow->next);
        slow->next = nullptr; // 断开前半部分和后半部分(可选,便于比较)

        // 3. 比较前后两部分
        ListNode *p1 = head, *p2 = secondHalf;
        bool result = true;
        while (p1 && p2) {
            if (p1->val != p2->val) {
                result = false;
                break;
            }
            p1 = p1->next;
            p2 = p2->next;
        }

        // 4. (可选)恢复链表结构
        slow->next = reverseList(secondHalf);

        return result;
    }

private:
    ListNode* reverseList(ListNode* head) {
        ListNode *prev = nullptr, *curr = head, *nextTemp = nullptr;
        while (curr) {
            nextTemp = curr->next;
            curr->next = prev;
            prev = curr;
            curr = nextTemp;
        }
        return prev;
    }
};

第二十题: 环形链表

题干 :判断单链表是否有环(节点可通过 next再次到达)。

核心:快慢指针(快指针走两步,慢指针走一步,相遇则有环)。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

class Solution {
public:
    bool hasCycle(ListNode *head) {
        if (!head || !head->next) return false;

        ListNode *slow = head;
        ListNode *fast = head;

        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;

            if (slow == fast) {
                return true;
            }
        }

        return false;
    }
};

第二十一题: 环形链表 II

题干 :找到环形链表中环的入口节点 (若无环返回 null)。

核心:快慢指针相遇后,一个指针回到头,两指针同速前进,相遇点即为环入口。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if (!head || !head->next) return nullptr;

        ListNode *slow = head, *fast = head;

        // 第一步:找相遇点,判断是否有环
        do {
            if (!fast || !fast->next) return nullptr; // 无环
            slow = slow->next;
            fast = fast->next->next;
        } while (slow != fast);

        // 第二步:找环入口
        slow = head; // slow 回到起点
        while (slow != fast) {
            slow = slow->next;
            fast = fast->next;
        }

        return slow; // 返回环入口节点
    }
};

第二十二题:合并两个有序链表

题干 :将两个升序链表合并为一个新的升序链表,返回新链表头节点。

核心:迭代法(新建虚拟头节点,依次拼接较小的节点)或递归法(合并剩余部分)。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        // 创建伪头节点
        ListNode dummy(0);
        ListNode* tail = &dummy;

        // 双指针遍历两个链表
        while (list1 != nullptr && list2 != nullptr) {
            if (list1->val <= list2->val) {
                tail->next = list1;
                list1 = list1->next;
            } else {
                tail->next = list2;
                list2 = list2->next;
            }
            tail = tail->next;
        }

        // 拼接剩余部分
        if (list1 != nullptr) {
            tail->next = list1;
        } else {
            tail->next = list2;
        }

        return dummy.next;
    }
};

第二十三题:两数相加

题干 :两个非负整数的链表(逆序存储每位数字),将它们相加,返回和的链表(同样逆序)。

核心:逐位相加,处理进位,注意链表长度不同时的补零。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* cur1 = l1, *cur2 = l2;
        ListNode* newhead = new ListNode(0); // 创建虚拟头结点
        ListNode* prev = newhead;             // 尾指针
        int t = 0;                            // 记录进位

        while (cur1 || cur2 || t) {
            // 加上第一个链表
            if (cur1) {
                t += cur1->val;
                cur1 = cur1->next;
            }
            // 加上第二个链表
            if (cur2) {
                t += cur2->val;
                cur2 = cur2->next;
            }
            // 创建新节点,存储当前位结果
            prev->next = new ListNode(t % 10);
            prev = prev->next;
            t /= 10; // 计算进位
        }

        prev = newhead->next;
        delete newhead; // 释放虚拟头结点
        return prev;
    }
};

第二十四题: 删除链表的倒数第 N 个结点

题干 :删除单链表的倒数第 n个节点,返回头节点。

核心 :双指针法(快指针先走 n步,然后快慢同走,快到末尾时慢指针指向待删节点的前一个)。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0); // 创建哑节点
        dummy->next = head;
        ListNode* fast = dummy;
        ListNode* slow = dummy;

        // 快指针先走 n 步
        for (int i = 0; i < n; i++) {
            fast = fast->next;
        }

        // 快慢指针同时走,直到快指针到末尾
        while (fast->next) {
            fast = fast->next;
            slow = slow->next;
        }

        // 删除倒数第 n 个节点
        ListNode* toDelete = slow->next;
        slow->next = slow->next->next;
        delete toDelete; // 可选:释放内存(C++)

        ListNode* result = dummy->next;
        delete dummy;    // 释放哑节点
        return result;
    }
};

第二十五题:两两交换链表中的节点

题干 :两两交换链表中的相邻节点,返回新头节点。要求只交换节点(不修改节点值)

核心:迭代法(虚拟头节点 + 三指针)或递归法(交换前两个节点,递归处理剩余)。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        // 边界情况
        if (!head || !head->next) return head;

        // 创建虚拟头节点
        ListNode* dummy = new ListNode(0);
        dummy->next = head;
        ListNode* prev = dummy;

        while (head && head->next) {
            ListNode* first = head;
            ListNode* second = head->next;

            // 交换节点指针
            prev->next = second;
            first->next = second->next;
            second->next = first;

            // 移动指针准备下一轮
            prev = first;
            head = first->next;
        }

        return dummy->next;
    }
};

第二十六题:复制带随机指针的链表

题干 :复制一个含 random指针的链表(每个节点有 valnextrandom),要求深拷贝,且新链表的 random指针与原链表对应节点一致。

核心:哈希表存储原节点与新节点的映射,或原地插入复制节点后再拆分。

C++ 复制代码
// Definition for a Node.
// class Node {
// public:
//     int val;
//     Node* next;
//     Node* random;
    
//     Node(int _val) {
//         val = _val;
//         next = nullptr;
//         random = nullptr;
//     }
// };

class Solution {
public:
    Node* copyRandomList(Node* head) {  
        if (head == nullptr) {
            return nullptr;
        }
        
        // 第一步:在每个原节点后面插入一个拷贝节点
        Node* pcur = head;
        while (pcur != nullptr) {
            Node* copyNode = new Node(pcur->val);
            copyNode->next = pcur->next;
            pcur->next = copyNode;
            pcur = copyNode->next;
        }
        
        // 第二步:设置拷贝节点的random指针
        pcur = head;
        while (pcur != nullptr) {
            Node* copyNode = pcur->next;
            if (pcur->random != nullptr) {
                copyNode->random = pcur->random->next;
            }
            pcur = copyNode->next;
        }
        
        // 第三步:拆分原链表和拷贝链表
        pcur = head;
        Node* newHead = head->next;
        Node* newTail = newHead;
        
        while (pcur != nullptr) {
            // 恢复原链表
            pcur->next = newTail->next;
            pcur = pcur->next;
            
            // 构建新链表
            if (pcur != nullptr) {
                newTail->next = pcur->next;
                newTail = newTail->next;
            }
        }
        
        return newHead;
    }
};

第二十七题: 排序链表

题干 :给定单链表头节点 head,将链表升序排列后返回。

C++ 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(!head||!head->next) return head;
        ListNode *slow=head;
        ListNode *fast=head->next;
        while(fast&&fast->next)
        {
            slow=slow->next;
            fast=fast->next->next;
        }
        ListNode* rightHead=slow->next;
        slow->next = nullptr;  // 断开

        ListNode* left = sortList(head);
        ListNode* right = sortList(rightHead);

        // 3. 合并两个有序链表
        return merge(left, right);
    }
    private:
    ListNode* merge(ListNode* l1, ListNode* l2) {
        ListNode dummy(0);
        ListNode* tail = &dummy;

        while (l1 && l2) {
            if (l1->val <= l2->val) {
                tail->next = l1;
                l1 = l1->next;
            } else {
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
        }

        tail->next = l1 ? l1 : l2;
        return dummy.next;
    }
};

第二十八题: LRU 缓存

题干 :设计实现 LRUCache数据结构,满足以下要求:

  • LRUCache(int capacity):以正整数 capacity为容量初始化缓存。

  • int get(int key):若 key存在则返回对应 value,否则返回 -1

  • void put(int key, int value):若 key存在则更新 value;否则插入键值对。若插入后缓存大小超过 capacity,则逐出最近最少使用的键值对。

  • getput操作的平均时间复杂度需为 O(1)

    C++ 复制代码
    class LRUCache {
    public:
        LRUCache(int capacity) : _capacity(capacity) {}
        int get(int key) {
            auto it = _hashmap.find(key);
            if (it == _hashmap.end()) return -1;
            // 移动到头部
            auto listit = it->second;
            pair<int, int> kv = *listit;
            _list.erase(listit);
            _list.push_front(kv);
            _hashmap[key] = _list.begin();
            return kv.second;
        }
        void put(int key, int value) {
            auto it = _hashmap.find(key);
    
            if (it == _hashmap.end()) {
                // 新增
                if (_list.size() >= _capacity) {
                    _hashmap.erase(_list.back().first); // 删除哈希记录
                    _list.pop_back();                   // 删除链表尾
                }
                _list.push_front({key, value});
                _hashmap[key] = _list.begin();
            } else {
                // 更新
                auto listit = it->second;
                pair<int, int> kv = *listit;
                kv.second = value;
                _list.erase(listit);
                _list.push_front(kv);
                _hashmap[key] = _list.begin();
            }
        }
    
    private:
        list<pair<int, int>> _list;
        size_t _capacity;
        unordered_map<int, list<pair<int, int>>::iterator> _hashmap;
    };

二叉树

第二十九题:二叉树的中序遍历

题干 :给定二叉树的根节点 root,返回它的中序遍历结果(左子树→根节点→右子树)。

示例

  • 输入:root = [1,null,2,3];输出:[1,3,2](中序遍历:1→3→2)。
C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        inorder(root, result);
        return result;
    }

private:
    void inorder(TreeNode* node, vector<int>& result) {
        if (node == nullptr) return;
        
        inorder(node->left, result);   // 1. 遍历左子树
        result.push_back(node->val);   // 2. 访问根节点
        inorder(node->right, result);  // 3. 遍历右子树
    }
};

第三十题:二叉树的最大深度

题干 :给定二叉树 root,求其最大深度(从根节点到最远叶子节点的最长路径上的节点数)。

示例

  • 输入:root = [3,9,20,null,null,15,7];输出:3(路径:3→20→15 或 3→20→7,长度3)。
C++ 复制代码
/*
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (root == nullptr) {
            return 0;
        }
        int leftDepth = maxDepth(root->left);
        int rightDepth = maxDepth(root->right);
        return max(leftDepth, rightDepth) + 1;
    }
};

第三十一题:对称二叉树

题干 :给定二叉树 root,判断它是否为对称二叉树(沿根节点的垂直中线折叠后,左右子树完全重合)。

示例

  • 输入:root = [1,2,2,3,4,4,3];输出:true(左右子树对称)。

    C++ 复制代码
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    public:
        bool isSymmetric(TreeNode* root) {
            if (!root) return true;
            return isMirror(root->left, root->right);
        }
    
    private:
        bool isMirror(TreeNode* left, TreeNode* right) {
            if (!left && !right) return true;
            if (!left || !right) return false;
            if (left->val != right->val) return false;
            return isMirror(left->left, right->right) && isMirror(left->right, right->left);
        }
    };

第三十二题:二叉树的层序遍历

题干 :给定二叉树 root,按层序遍历(从顶部到底部,每层从左到右)返回节点值的列表。

示例

  • 输入:root = [3,9,20,null,null,15,7];输出:[[3],[9,20],[15,7]](逐层输出)。
C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> result;
        if(!root) return result;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty())
        {
            int levelSize=q.size();
            vector<int> currentLevel;
            for(int i=0;i<levelSize;i++)
            {
                TreeNode* node=q.front();
                q.pop();
                currentLevel.push_back(node->val);
                if(node->left) q.push(node->left);
                if(node->right) q.push(node->right);
            }
            result.push_back(currentLevel);
        }
        return result;
    }
};

第三十三题:将有序数组转换为二叉搜索树

题干 :给定升序数组 nums,将其转换为一棵高度平衡的二叉搜索树(左右子树高度差≤1,且左子树所有节点<根<右子树所有节点)。

示例

  • 输入:nums = [-10,-3,0,5,9];输出:[0,-3,9,-10,null,5](平衡BST)。
C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        // 入口函数:调用递归辅助函数,初始范围是整个数组
        return buildBST(nums, 0, nums.size() - 1);
    }

private:
    // 递归辅助函数:在区间 [left, right] 上构建 BST
    TreeNode* buildBST(vector<int>& nums, int left, int right) {
        // 基础情况:如果左边界超过右边界,说明没有元素可构建,返回空
        if (left > right) {
            return nullptr;
        }

        // 取中间位置(防止整数溢出,推荐使用 left + (right - left) / 2)
        int mid = left + (right - left) / 2;

        // 创建根节点
        TreeNode* root = new TreeNode(nums[mid]);

        // 递归构建左子树(左半部分)
        root->left = buildBST(nums, left, mid - 1);

        // 递归构建右子树(右半部分)
        root->right = buildBST(nums, mid + 1, right);

        // 返回当前构建好的子树的根节点
        return root;
    }
};

第三十四题: 二叉树的右视图

题干 :给定二叉树 root,返回从右侧观察能看到的节点值(即每层最右边的节点)。

示例

  • 输入:root = [1,2,3,null,5,null,4];输出:[1,3,4](每层最右节点:1→3→4)。
C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        vector<int> result;
        if (!root) return result;

        queue<TreeNode*> q;
        q.push(root);

        while (!q.empty()) {
            int levelSize = q.size(); // 当前层的节点数

            for (int i = 0; i < levelSize; ++i) {
                TreeNode* curr = q.front();
                q.pop();

                // 如果是当前层的最后一个节点,加入结果
                if (i == levelSize - 1) {
                    result.push_back(curr->val);
                }

                // 先左后右入队(保证下一层从左到右处理)
                if (curr->left) q.push(curr->left);
                if (curr->right) q.push(curr->right);
            }
        }

        return result;
    }
};

第三十五题: 翻转二叉树

题干 :给定二叉树 root翻转该树(每个节点的左右子树交换位置),返回翻转后的根节点。

示例

  • 输入:root = [4,2,7,1,3,6,9];输出:[4,7,2,9,6,3,1](左右子树交换)。
C++ 复制代码
**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        // 基础情况:空节点直接返回
        if (!root) return nullptr;

        // 递归翻转左右子树
        TreeNode* left = invertTree(root->left);
        TreeNode* right = invertTree(root->right);

        // 交换左右子树
        root->left = right;
        root->right = left;

        return root;
    }
};

第三十六题: 二叉树的直径

题干 :给定二叉树 root,求其直径(任意两节点之间最长路径的边数,路径可能不经过根节点)。

示例

  • 输入:root = [1,2,3,4,5];输出:3(路径:4→2→5 或 5→2→1→3,边数3)。
C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int diameterOfBinaryTree(TreeNode* root) {
        int m=0;
        dfs(root,m);
        return m;
    }
private:
    int dfs(TreeNode* node,int &m)
    {
        if(!node) return 0;
        int dleft=dfs(node->left,m);
        int dright=dfs(node->right,m);
        m=max(m,dleft+dright);
        return max(dleft,dright)+1;
    }
};

第三十七题:二叉搜索树中第 K 小的元素

题干 :给定二叉搜索树 root和整数 k,返回树中第 k 小的元素(按升序排列的第 k 个节点值)。

示例

  • 输入:root = [3,1,4,null,2], k=1;输出:1(升序:1→2→3→4,第1小是1)。
C++ 复制代码
class Solution {
public:
    int kthSmallest(TreeNode* root, int k) {
        int result = 0;
        inorder(root, k, result);
        return result;
    }

private:
    void inorder(TreeNode* node, int& k, int& result) {
        if (!node) return;
        
        inorder(node->left, k, result);  // 左
        k--;                              // 访问当前节点,计数减一
        if (k == 0) {                     // 找到第k个
            result = node->val;
            return;
        }
        inorder(node->right, k, result); // 右
    }
};

第三十八题:验证二叉搜索树

题干 :给定二叉树 root,判断它是否为有效二叉搜索树(左子树所有节点<根,右子树所有节点>根,且子树自身也满足BST)。

示例

  • 输入:root = [2,1,3];输出:true(1<2<3,子树合法)。
C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isValidBST(TreeNode* root) {
        long long prev=LLONG_MIN;
        return inorder(root,prev);
    }
private:
    bool inorder(TreeNode *node,long long&prev)
    {
        if (!node) return true;

        // 遍历左子树
        if (!inorder(node->left, prev)) return false;

        // 检查当前节点是否大于前一个节点
        if (node->val <= prev) return false;
        prev = node->val; // 更新前一个值

        // 遍历右子树
        return inorder(node->right, prev);
    }
};

第三十九题:路径总和 III

题干 :给定二叉树的根节点 root和整数 targetSum,求该二叉树里节点值之和等于 targetSum路径数目。路径不需要从根节点开始,也不需要在叶子节点结束,但路径方向必须是向下的(只能从父节点到子节点)。

C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int pathSum(TreeNode* root, int targetSum) {
        if(!root) return 0;
        //从当前节点开始
        int count=dfs(root,targetSum);
        count+=pathSum(root->left,targetSum);
        count+=pathSum(root->right,targetSum);
        return count;
    }
private:
    int dfs(TreeNode* node,long long target)
    {
        if(!node) return 0;
        int count=0;
        if(node->val==target)  count++;
        // 继续向下找,目标和减去当前节点值
        count += dfs(node->left, target - node->val);
        count += dfs(node->right, target - node->val);
        
        return count;
    }
};

第四十题:二叉树的最近公共祖先

题干 :给定二叉树的两个节点 pq,找到它们的最近公共祖先 (LCA)。最近公共祖先定义为:一个节点 x,满足 xpq的祖先,且 x的深度尽可能大(节点本身也可以是自己的祖先)。

C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (!root) return nullptr;
        if (p == root || q == root) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if (right && left) return root;
        if (left) return left;
        if (right) return right;
        return nullptr; 
    }
};

第四十一题:从前序与中序遍历序列构造二叉树

题干 :给定两个整数数组 preorder(先序遍历)和 inorder(中序遍历),构造该二叉树并返回其根节点。

C++ 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        // 建立值到索引的映射,加速查找
        unordered_map<int, int> indexMap;
        for (int i = 0; i < inorder.size(); ++i) {
            indexMap[inorder[i]] = i;
        }

        // 递归函数:传入前序和中序的左右边界
        function<TreeNode*(int, int, int, int)> dfs = [&](int preLeft, int preRight, int inLeft, int inRight) -> TreeNode* {
            // 递归终止条件
            if (preLeft > preRight || inLeft > inRight) return nullptr;

            // 前序第一个元素是当前根节点
            int rootVal = preorder[preLeft];
            TreeNode* root = new TreeNode(rootVal);

            // 在中序中找到根节点位置
            int rootIdx = indexMap[rootVal];

            // 计算左子树节点数
            int leftSize = rootIdx - inLeft;

            // 递归构建左子树:前序[preLeft+1, preLeft+leftSize],中序[inLeft, rootIdx-1]
            root->left = dfs(preLeft + 1, preLeft + leftSize, inLeft, rootIdx - 1);

            // 递归构建右子树:前序[preLeft+leftSize+1, preRight],中序[rootIdx+1, inRight]
            root->right = dfs(preLeft + leftSize + 1, preRight, rootIdx + 1, inRight);

            return root;
        };

        return dfs(0, preorder.size() - 1, 0, inorder.size() - 1);
    }
};

第四十二题:二叉树展开为链表

题干 :给定二叉树的根节点 root,将其展开为一个单链表。展开后的链表应使用 TreeNode,其中 right指针指向链表的下一个节点,left指针始终为 null。链表应与二叉树的先序遍历顺序相同。

C++ 复制代码
class Solution {
public:
    void flatten(TreeNode* root) {
        if (!root) return;

        // 递归展开左右子树
        flatten(root->left);
        flatten(root->right);

        // 暂存右子树
        TreeNode* right = root->right;

        // 将左子树移到右子树位置
        root->right = root->left;
        root->left = nullptr;

        // 找到当前右链表的末尾
        TreeNode* p = root;
        while (p->right) {
            p = p->right;
        }

        // 接上原右子树
        p->right = right;
    }
};

图论

第四十三题:岛屿数量

给定由 '1'(陆地)和 '0'(水)组成的二维网格,计算岛屿数量。岛屿定义为水平/竖直方向相邻的陆地,且网格四边均被水包围。

C++ 复制代码
class Solution {
    int m, n;
    int dx[4] = {0, 0, -1, 1};
    int dy[4] = {1, -1, 0, 0};
    
public:
    int numIslands(vector<vector<char>>& grid) {
        if(grid.empty() || grid[0].empty()) return 0;
        m = grid.size(), n = grid[0].size();
        
        int ret = 0;
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++) {
                if(grid[i][j] == '1') {
                    ret++;
                    dfs(grid, i, j);
                }
            }
        return ret;
    }
    
private:
    void dfs(vector<vector<char>>& grid, int i, int j) {
        if(i < 0 || i >= m || j < 0 || j >= n || grid[i][j] != '1')
            return;
        
        grid[i][j] = '0';  // 标记为已访问
        
        for(int k = 0; k < 4; k++) {
            int x = i + dx[k], y = j + dy[k];
            dfs(grid, x, y);
        }
    }
};

第四十四题: 腐烂的橘子

m×n网格中,单元格值 0(空)、1(新鲜橘子)、2(腐烂橘子)。每分钟,腐烂橘子会使其上下左右相邻 的新鲜橘子腐烂。求所有橘子腐烂所需的最小分钟数 ;若存在新鲜橘子永远无法腐烂(与腐烂橘子不连通),返回 -1

C++ 复制代码
class Solution {
public:
    int orangesRotting(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        queue<pair<int, int>> q;
        int fresh = 0; // 新鲜橘子计数
        int time = 0;  // 腐烂所需时间

        // 初始化:找到所有腐烂橘子入队,统计新鲜橘子
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 2) {
                    q.push({i, j});
                } else if (grid[i][j] == 1) {
                    fresh++;
                }
            }
        }

        // 特判:如果没有新鲜橘子,直接返回0
        if (fresh == 0) return 0;

        // 四个方向:上、下、左、右
        vector<pair<int, int>> dirs = {{-1,0}, {1,0}, {0,-1}, {0,1}};

        // BFS 多源扩散
        while (!q.empty()) {
            int size = q.size();
            bool rottenThisRound = false;

            for (int k = 0; k < size; k++) {
                auto [x, y] = q.front(); q.pop();

                for (auto& dir : dirs) {
                    int nx = x + dir.first, ny = y + dir.second;
                    if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == 1) {
                        grid[nx][ny] = 2; // 标记为腐烂
                        q.push({nx, ny});
                        fresh--;          // 新鲜橘子减少
                        rottenThisRound = true;
                    }
                }
            }

            // 如果本轮有感染发生,时间+1
            if (rottenThisRound) time++;
        }

        // 如果还有新鲜橘子没被感染,说明无法全部腐烂
        return fresh == 0 ? time : -1;
    }
};

第四十五题: 课程表

给定 numCourses门课程(编号 0~numCourses-1)和先修关系数组 prerequisitesprerequisites[i] = [a_i, b_i]表示学 a_i前需先学 b_i)。判断是否能完成所有课程(即先修关系无循环依赖)。

C++ 复制代码
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //构建邻接表和入度数组
        vector<vector<int>> graph(numCourses);
        vector<int> indegree(numCourses,0);

        for(auto& pre:prerequisites)
        {
            int course=pre[0];
            int prereq=pre[1];
            graph[prereq].push_back(course);
            indegree[course]++;
        }

        queue<int> q;
        for(int i=0;i<numCourses;i++)
        {
            if(indegree[i]==0)
            {
                q.push(i);
            }
        }
        int visited=0;
        while(!q.empty())
        {
            int cur=q.front();
            q.pop();
            visited++;
            for(int next:graph[cur])
            {
                indegree[next]--;
                if(indegree[next]==0)
                {
                    q.push(next);
                }
            }
        }
        return visited==numCourses;
    }
};

第四十六题:实现 Trie(前缀树)

实现前缀树(Trie)数据结构,支持以下操作:

  • insert(word):插入字符串 word
  • search(word):判断 word是否已插入(精确匹配);
  • startsWith(prefix):判断是否存在已插入的字符串以 prefix为前缀。
C++ 复制代码
class Trie {
private:
    struct TrieNode {
        bool isEnd;
        TrieNode* children[26];
        TrieNode() {
            isEnd = false;
            for (int i = 0; i < 26; i++) {
                children[i] = nullptr;
            }
        }
    };
    TrieNode* root;

public:
    Trie() {
        root = new TrieNode();
    }

    void insert(string word) {
        TrieNode* node = root;
        for (char ch : word) {
            int idx = ch - 'a';
            if (node->children[idx] == nullptr) {
                node->children[idx] = new TrieNode();
            }
            node = node->children[idx];
        }
        node->isEnd = true;
    }

    bool search(string word) {
        TrieNode* node = root;
        for (char ch : word) {
            int idx = ch - 'a';
            if (node->children[idx] == nullptr) {
                return false;
            }
            node = node->children[idx];
        }
        return node->isEnd;
    }

    bool startsWith(string prefix) {
        TrieNode* node = root;
        for (char ch : prefix) {
            int idx = ch - 'a';
            if (node->children[idx] == nullptr) {
                return false;
            }
            node = node->children[idx];
        }
        return true;
    }
};
/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj->insert(word);
 * bool param_2 = obj->search(word);
 * bool param_3 = obj->startsWith(prefix);
 */
相关推荐
漫随流水2 小时前
c++编程:反转字符串(leetcode344)
数据结构·c++·算法
南境十里·墨染春水2 小时前
C++ 笔记 友元(面向对象)
开发语言·c++·笔记
C++ 老炮儿的技术栈3 小时前
分享一个安全的CString
c语言·c++·windows·git·安全·visual studio
穿条秋裤到处跑3 小时前
每日一道leetcode(2026.03.31):字典序最小的生成字符串
算法·leetcode
桦03 小时前
[C++复习]:STL
开发语言·c++
苏宸啊4 小时前
rbtree封装map和set
c++
汉克老师5 小时前
GESP2025年6月认证C++三级( 第一部分选择题(1-8))
c++·二进制·原码·补码·gesp三级·gesp3级·八进制、
不想写代码的星星5 小时前
C++ 折叠表达式:“我写递归你写折叠,咱俩代码差十年”
c++
Titan20245 小时前
map和set的封装学习笔记
数据结构·c++