4.12

102. 二叉树的层序遍历 - 力扣(LeetCode)

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        queue<TreeNode*> que;
        if(!root) return res;
        que.push(root);
        while(!que.empty()){
            int size = que.size();
            vector<int> vec;
            for (int i = 0; i < size; i++) {
               TreeNode* node = que.front();
               que.pop();
               vec.push_back(node->val);
               if(node->left)  que.push(node->left);
               if(node->right) que.push(node->right);
            }
            res.push_back(vec);
        }
        return res;
    }
};

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

设 x=nums[mid] 是现在二分取到的数。

我们需要判断 x 和数组最小值的位置关系,谁在左边,谁在右边?

把 x 与最后一个数 nums[n−1] 比大小:

  • 如果 x > nums[n−1],那么可以推出以下结论:
    • nums 一定被分成左右两个递增段;
    • 第一段的所有元素均大于第二段的所有元素;
    • x 在第一段。
    • 最小值在第二段。
    • 所以 x 一定在最小值的左边
  • 如果 x≤nums[n−1],那么 x 一定在第二段。(或者 nums 就是递增数组,此时只有一段。)
    • x 要么是最小值,要么在最小值右边

所以,只需要比较 x 和 nums[n−1] 的大小关系,就间接地知道了 x 和数组最小值的位置关系,从而不断地缩小数组最小值所在位置的范围,二分找到数组最小值。

//开区间二分(-1 , n-1)
class Solution {
    public:
        int findMin(vector<int>& nums) {
            int n = nums.size();
            int l = -1 , r = n - 1;//开区间(-1 , n - 1)
            while(l + 1 < r){
                int mid = (l + r) >> 1;
                if(nums[mid] >= nums[n - 1]) l = mid;
                else  r = mid;
              //这一段也可写为:
              //(nums[mid] < nums.back() ? r : l) = mid;
                                 
            }
            return nums[r];
        }
    };

2. 两数相加 - 力扣(LeetCode)

本题的链表是从数字的最低位开始的

方法一:递归

把虚线内要计算的内容,可以理解为一个和原问题相似的,规模更小的子问题,所以非常适合用递归解决。

每次把两个节点值 l1.val, l2.val 与进位值 carry 相加,除以 10 的余数即为当前节点需要保存的数位,除以 10 的商即为新的进位值。

代码实现时,有一个简化代码的小技巧:如果递归中发现 l2 的长度比 l1 更长,那么可以交换 l1 和 l2,保证 l1 不是空节点,从而简化代码逻辑。

class Solution {
public:
    // l1 和 l2 为当前遍历的节点,carry 为进位
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2, int carry = 0) {
        if (l1 == nullptr && l2 == nullptr) { // 递归边界:l1 和 l2 都是空节点
            return carry ? new ListNode(carry) : nullptr; // 如果进位了,就额外创建一个节点
        }
        if (l1 == nullptr) { // 如果 l1 是空的,那么此时 l2 一定不是空节点
            swap(l1, l2); // 交换 l1 与 l2,保证 l1 非空,从而简化代码
        }
        int sum = carry + l1->val + (l2 ? l2->val : 0); // 节点值和进位加在一起
        l1->val = sum % 10; // 每个节点保存一个数位(直接修改原链表)
        l1->next = addTwoNumbers(l1->next, (l2 ? l2->next : nullptr), sum / 10); // 进位
        return l1;
    }
};

方法二:迭代

迭代的思路是,初始化答案为一个「空链表」,每次循环,向该链表末尾添加一个节点(保存一个数位)。

循环即遍历链表 l1 和 l2,每次把两个节点值 l1.val, l2.val 与进位值 carry 相加,除以 10 的余数即为当前节点需要保存的数位,除以 10 的商即为新的进位值。

需要注意的是,在第一次循环时,我们无法往一个空节点的末尾添加节点。这里的技巧是,创建一个哨兵节点(dummy node),当成初始的「空链表」。循环结束后,哨兵节点的下一个节点就是最终要返回的链表头节点。

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode dummy; // 哨兵节点
        ListNode* cur = &dummy;
        int carry = 0; // 进位
        while (l1 || l2 || carry) { // 有一个不是空节点,或者还有进位,就继续迭代
            if (l1) {
                carry += l1->val; // 节点值和进位加在一起
                l1 = l1->next; // 下一个节点
            }
            if (l2) {
                carry += l2->val; // 节点值和进位加在一起
                l2 = l2->next; // 下一个节点
            }  
            cur = cur->next = new ListNode(carry % 10); // 每个节点保存一个数位
            carry /= 10; // 新的进位
        }
        return dummy.next; // 哨兵节点的下一个节点就是头节点
    }
};

补充题6. 手撕堆排序

class Solution {
   // 维护最大堆性质(正确实现)
    void maxHeapify(vector<int>& a, int i, int heapSize) {
        int l = i * 2 + 1;    // 左子节点索引
       int r = i * 2 + 2;    // 右子节点索引
        int largest = i;      // 记录最大值的索引

        // 比较左子节点
        if (l < heapSize && a[l] > a[largest]) 
            largest = l;

        // 比较右子节点
        if (r < heapSize && a[r] > a[largest])
            largest = r;

        // 若子节点更大,交换并递归调整
        if (largest != i) {
            swap(a[i], a[largest]);
            maxHeapify(a, largest, heapSize);
        }
    }

    // 构建最大堆
    void buildMaxHeap(vector<int>& a, int heapSize) {
        // 从最后一个非叶子节点开始调整
        for (int i = heapSize / 2 - 1; i >= 0; --i) {
            maxHeapify(a, i, heapSize);
        }
    }

public:
    vector<int> sortArray(vector<int>& nums) {
        int n = nums.size();

        // 1. 构建初始最大堆
        buildMaxHeap(nums, n);

        // 2. 逐步提取最大值并调整堆
        for (int i = n - 1; i > 0; --i) {
            swap(nums[0], nums[i]);  // 将当前最大值移到末尾
            maxHeapify(nums, 0, i);  // 调整剩余元素的堆结构
        }

        return nums;
    }
};

46. 全排列 - 力扣(LeetCode)

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>> res;
        vector<int> vec;
        vector<int> used(nums.size() , false);

        auto dfs = [&](this auto&& dfs){
           if(vec.size() == nums.size()){
            res.emplace_back(vec);
            return;
           }
            for (int i = 0; i < nums.size(); i++) {
               if(used[i])  continue;

               used[i] = true;
               vec.push_back(nums[i]);
               dfs();
               vec.pop_back();
               used[i] = false;
            }
            
        };
        dfs();
        return res;
    }
};
posted @ 2025-04-15 22:50  七龙猪  阅读(1)  评论(0)    收藏  举报
-->