【机试c++】力扣题目练习合集

参考题单:LeetCode 热题 100

哈希表(unordered_map、unordered_set)

1. 两数之和

代码中的 x 不是一个 pair 对象,而是一个指针 / 迭代器(iterator),需要用->来调用。
如果是增强for循环遍历得到的就是pair对象,可以用.调用。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> a; // (数据,索引)
        for(int i = 0;i < nums.size();i++){
            auto x = a.find(target - nums[i]);
            // mp.find(key); 查找key,返回迭代器,找不到返回end()
            if(x != a.end()) return {x->second, i};
            a[nums[i]] = i; // 放入map
        }
        return {};
    }
};

49. 字母异位词分组

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> mp;
        for(int i = 0;i < strs.size();i++){
            string s = strs[i];
            sort(s.begin(), s.end());
            mp[s].push_back(strs[i]); // 键值对mp[s]是一个vector,将strs[i]加入这个vector
        }
        vector<vector<string>> ans;
        for(pair<const string, vector<string>>& p : mp){
            // 其中 key 必须是 const,因为 map 的 key 不能被你通过迭代器直接修改。
            ans.push_back(p.second);
        }
        return ans;
    }
};

128. 最长连续序列

如果有比 x 更小的数,那么在这个子序列里面,就还没有找到它的起始点。

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> a;
        for(int x : nums) a.insert(x);
        int ans = 0;
        for(int x : a){
            if(!a.count(x - 1)){ // 当前数最小,没有比它小的
                int n = x;
                while(a.count(n)) n++; // 找比x大的连续数,直到没有,此时n-1是最大的连续数
                ans = max(ans, n - x); // 连续子序列长度为 n-1 - x + 1
            }
        }
        return ans;
    }
};

矩阵

54. 螺旋矩阵,蛇形矩阵

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int d[4][2] = {{0,1},{1,0},{0,-1},{-1,0}}; // 右下左上
        int n = matrix.size(); // 行
        int m = matrix[0].size(); //列
        int dis = 0; // 当前遍历方向
        vector<int> ans(m * n);
        int i = 0, j = 0;
        for(int k = 0;k < m * n;k++){
            ans[k] = matrix[i][j];
            matrix[i][j] = INT_MAX;
            int x = i + d[dis][0];
            int y = j + d[dis][1]; // 判断这个方向是否超纲
            if(x < 0 || x >= n || y < 0 || y >= m || matrix[x][y] == INT_MAX){
                dis = (dis + 1) % 4; // 更新遍历方向
            }
            i += d[dis][0]; // 确认完方向之后,真正的更新坐标
            j += d[dis][1];
        }
        // cout << INT_MAX; // 2147483647
        return ans;
    }
};

链表

  • ListNode* a = new ListNode(1);中new ListNode(1)返回的是指针,需要ListNode*接受。
  • ListNode a(1);才是定义一个对象,赋值next的时候使用引用a.next = &b,赋值val使用a.val = 10。

160. 相交链表

参考题解:160. 相交链表(双指针,清晰图解)

简单来说,就是同时遍历两个链表,遍历完自己之后,遍历另外一个链表,直至两个链表节点相等,即为第一个公共节点。(天才想法,太厉害了)

  • 如果两个链表有公共部分,则相遇时是第一个节点;
  • 如果没有,则相遇时,两个遍历的节点将A、B两个链表都遍历完,A == B == NULL。
/**
 * 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) {
        // 定义两个指针,不是重新创建两个节点。
        // 使A、B 作为遍历指针,而不直接修改 headA、headB。
        ListNode* A = headA;
        ListNode* B = headB;
        while(A != B){
            A = (A == NULL) ? headB : A->next;
            B = (B == NULL) ? headA : B->next;
        }
        return A;
    }
};

206. 反转链表

/**
 * 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){
            ListNode* next = curr->next;  // ① 先保存下一个节点
            curr->next = prev;            // ② 当前节点指向前一个节点
            prev = curr;                  // ③ prev 向后移动(指向新链表的头节点)
            curr = next;                  // ④ curr 向后移动(继续遍历原节点)
        }
        return prev;
    }
};

234. 回文链表

/**
 * 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) {
        // 快慢指针:找链表中间节点(用于给链表后半部分反转)
        ListNode* slow = head, *fast = head; 
        while(fast && fast -> next){
            slow = slow->next;
            fast = fast->next->next;
        }
        // 反转链表后半部分
        ListNode* pre = nullptr, *curr = slow;
        while(curr){
            ListNode* next = curr->next;
            curr->next = pre;
            pre = curr;
            curr = next;
        }
        // 开始比较
        ListNode* p1 = head, *p2 = pre;
        while(p1 && p2){
            if(p1->val != p2->val) return false;
            p1 = p1->next;
            p2 = p2->next;
        }
        return true;
    }
};

141. 环形链表

环状链表快慢指针问题,

  • 如果不存在环,那么fast先到链表结尾且始终不存在fast == slow,直到循环结束对吗
  • 如果存在环,当fast先进入环中,一定会追赶上slow,最终二者相遇
/**
 * 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) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast -> next){
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast) return true;
        }
        return false;
    }
};

写一个完整的自测试代码,注意

  • ListNode* a = new ListNode(1);中new ListNode(1)返回的是指针,需要ListNode*接受。
  • ListNode a(1)才是定义一个对象,赋值next的时候使用引用a.next = &b,赋值val使用a.val = 10。
点击查看代码
#include <iostream>
using namespace std;

// 链表节点
struct ListNode {
    int val;
    ListNode* next;

    ListNode(int x) : val(x), next(nullptr) {}
};

// 判断链表是否有环
bool hasCycle(ListNode* head) {
    ListNode* fast = head;
    ListNode* slow = head;

    while (fast && fast->next) {
        slow = slow->next;           // 慢指针走一步
        fast = fast->next->next;     // 快指针走两步

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

    return false;
}

int main() {

    // =========================
    // 测试1:无环链表
    // 1 -> 2 -> 3 -> 4 -> nullptr
    // =========================
    ListNode* a = new ListNode(1);
    ListNode* b = new ListNode(2);
    ListNode* c = new ListNode(3);
    ListNode* d = new ListNode(4);

    a->next = b;
    b->next = c;
    c->next = d;
    d->next = nullptr;

    cout << "测试1:";
    cout << (hasCycle(a) ? "有环" : "无环") << endl;


    // =========================
    // 测试2:有环链表
    // 1  ->  2  -> 3   ->   4
    //             ↑        ↓
    //             └────┘
    // =========================
    ListNode* e = new ListNode(1);
    ListNode* f = new ListNode(2);
    ListNode* g = new ListNode(3);
    ListNode* h = new ListNode(4);

    e->next = f;
    f->next = g;
    g->next = h;
    h->next = g;  // 4重新指向3,形成环

    cout << "测试2:";
    cout << (hasCycle(e) ? "有环" : "无环") << endl;

    return 0;
}

142. 环形链表 II

题解:灵茶山艾府,天才!

/**
 * 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) {
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast && fast -> next){
            slow = slow->next;
            fast = fast->next->next;
            ListNode* head2 = head;
            if(slow == fast){ // 和fast相遇后slow再走a步到入环点,head从头走a步到入环点,二者相遇
                while(slow != head2){
                    slow = slow->next;
                    head2 = head2->next;
                }
                return slow;
            }
        }
        return nullptr;
    }
};

21. 合并两个有序链表

/**
 * 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* head = new ListNode(); // 头节点,head->next才是真正的第一个节点
        ListNode* prev = head;
        while(list1 != nullptr && list2 != nullptr){
            if(list1->val < list2->val){
                prev->next = list1;
                list1 = list1->next;
            }else{
                prev->next = list2;
                list2 = list2->next;
            }
            prev = prev->next; // 指向尾结点
        }
        // 直接将链表末尾指向未合并完的链表即可
        prev->next = (list1 == nullptr) ? list2 : list1;
        return head->next;
    }
};

2. 两数相加

/**
 * 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* head = new ListNode();
        ListNode* curr = head;
        int t = 0; // 进位
        while(l1 || l2 || t){
            int sum = t; //两数之和 + 进位
            if(l1){
                sum += l1->val;
                l1 = l1->next;
            }
            if(l2){
                sum += l2->val;
                l2 = l2->next;
            }
            ListNode* node = new ListNode(sum % 10);
            curr->next = node;
            curr = curr->next;//遍历到新链表的尾部
            t = sum / 10; // 保留进位
        }
        return head->next;
    }
};

19. 删除链表的倒数第 N 个结点

向有一个指针走n步,然后新加入一个指针一起向下同速遍历,当第一个指针遍历到链表结束,第二个指针就到倒数第n个节点的前一个位置了。

由于可能会删除链表头部,所以新创建一个头节点,两个指针都从这个新头节点开始遍历,而不是从原头节点开始遍历。

/**
 * 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* newHead = new ListNode();
        newHead->next = head;
        ListNode* first = newHead;
        ListNode* second = newHead;
        while(n--) first = first->next;
        while(first->next){
            first = first->next;
            second = second->next;
        }
        // 此时已经到倒数第n+1个节点
        ListNode* x = second->next;
        second->next = second->next->next;
        delete x;
        return newHead->next;
    }
};

24. 两两交换链表中的节点

image

法一

/**
 * 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) {
        ListNode* newHead = new ListNode(0, head); // val没有用,next指向head
        ListNode* n0 = newHead;
        ListNode* n1 = head;
        while(n1 && n1->next){
            ListNode* n2 = n1->next;
            ListNode* n3 = n2->next;
            n0->next = n2;
            n2->next = n1;
            n1->next = n3; // 由于上一行n2->next已经更新,所以需要用n3记录原n2->next
            // 节点位置变化:n0 n1 n2 (n3)  → n0 n2 n1 (n3)
            n0 = n1; // 向下移动两个节点
            n1 = n3;
        }
        return newHead->next;
    }
};

法二

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* newHead = new ListNode(0, head); // val没有用,next指向head
        ListNode* n0 = newHead;
        ListNode* n1 = head;
        while(n1 && n1->next){
            ListNode* n3 = n1->next->next;
            n0->next = n1->next;
            n1->next->next = n1;
            n1->next = n3; // 由于上一行n2->next已经更新,所以需要用n3记录原n2->next
            // 节点位置变化:n0 n1 n2 (n3)  → n0 n2 n1 (n3)
            n0 = n1; // 向下移动两个节点
            n1 = n3;
        }
        return newHead->next;
    }
};

138. 随机链表的复制

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        // 复制每个节点,把新节点直接插到原节点的后面
        for(Node* cur = head;cur;cur = cur->next->next){
            cur->next = new Node(cur->val, cur->next,nullptr);
        }
        // 遍历交错链表中的原链表节点
        for(Node* cur = head;cur;cur = cur->next->next){
            // 要复制的 random 是 cur->random 的下一个节点
            if(cur->random) cur->next->random = cur->random->next;
        }
        // 把交错链表分离成两个链表
        Node* newHead = new Node(0);
        Node* t = newHead;
        for(Node* cur = head;cur;cur = cur->next, t = t->next){
            Node* copy = cur->next;//复制的新节点
            t->next = copy; // 把新节点插在 t 的后面,构建新的链表
            cur->next = copy->next; // 恢复原节点的 next
        }
        return newHead->next;
    }
};

25. K 个一组翻转链表

image

/**
 * 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* reverseKGroup(ListNode* head, int k) {
        int n = 0;
        for(ListNode* cur = head;cur;cur = cur->next) n++;
        ListNode* nh = new ListNode(0, head);
        ListNode* tail = nh; // 每组数的前一个节点(上一组的尾结点)
        for(int i = 0;n - i >= k;i += k){
            ListNode* pre = nullptr;
            ListNode* cur = tail->next; // 下一组k个节点的前一个
            // k个节点的反转
            for(int j = 0;j < k;j++){
                ListNode* next = cur->next;
                cur->next = pre;
                pre = cur;
                cur = next;
            }
            // 此时,cur 是下一组的起始节点,pre 是当前组的头节点
            ListNode* t = tail->next; // 存一下当前组的尾结点(反转前的头节点)
            tail->next->next = cur; // 将反转后的当前组的尾结点接到下一组上
            tail->next = pre; // 将上一组的尾结点接到反转后的当前组的头节点上
            tail = t; // 更新下一组的前一个节点,用于下次遍历找到下一组的头节点
        }
        return nh->next;
    }
};

二叉树

94. 二叉树的中序遍历【三种遍历】

三种遍历方式的方法类似,只需要改变递归函数中三个语句的顺序

  • 先序遍历:根左右
  • 中序遍历:左根右
  • 后序遍历:左右根
/**
 * 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:
    void inoreder(TreeNode* root, vector<int>& ans){
        if(!root) return;
        // 左右根
        inoreder(root->left, ans);
        ans.push_back(root->val);
        inoreder(root->right, ans);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        inoreder(root, ans);
        return ans;
    }
};

104. 二叉树的最大深度

/**
 * 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) return 0;
        return max(maxDepth(root->left) + 1, maxDepth(root->right) + 1);
    }
};

226. 翻转二叉树

/**
 * 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* l = invertTree(root->left);
        TreeNode* r = invertTree(root->right);
        root->left = r;
        root->right = l;
        return root;
    }
};

101. 对称二叉树

/**
 * 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 check(TreeNode* l, TreeNode* r){
        if(!l && !r) return true; // 都不存在
        if(l && r && l->val == r->val) // 都存在且值相等,继续遍历左右子树
            return check(l->left, r->right) && check(l->right, r->left);
        return false;
    }
    bool isSymmetric(TreeNode* root) {
        return check(root->left, root->right);
    }
};

543. 二叉树的直径

/**
 * 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 ans = 0;
    int dfs(TreeNode* root){
        if(!root) return -1; // 对于叶子来说,左、右链长都是 -1+1=0
        // 这里的长度实际上是按照边数计算的。
        int l_len = dfs(root->left) + 1;
        int r_len = dfs(root->right) + 1;
        ans = max(ans, l_len + r_len); // 两条链拼成路径
        return max(l_len, r_len); // 当前子树最大链长
    }
    int diameterOfBinaryTree(TreeNode* root) {
        dfs(root);
        return ans;
    }
};

102. 二叉树的层序遍历

/**
 * 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>> ans;
        if(!root) return ans;

        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            vector<int> level;
            int n = q.size();
            while(n-- > 0){
                TreeNode* t = q.front();
                q.pop();
                level.push_back(t->val);
                if(t->left) q.push(t->left);
                if(t->right) q.push(t->right);
            }
            ans.push_back(level);
        }
        return ans;
    }
};

105. 从前序与中序遍历序列构造二叉树【前序 + 中序 → 构造】【后序 + 中序 → 构造】

前序 + 中序 → 构造

/**
 * 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:
    unordered_map<int, int> mp;// 记录每个节点在中序遍历中的索引
    TreeNode* buid(const vector<int>& preorder, const vector<int>& inorder,
        int preStart, int preEnd, int inStart, int inEnd){
        // 前序、中序的起始节点作为参数
        if(preStart > preEnd) return nullptr;
        int root = preorder[preStart]; // 前序的根节点就是整个二叉树的根节点
        int index = mp[root]; // 获取根节点在中序遍历中的位置

        TreeNode* ans = new TreeNode(root); // 创建根节点
        int left = index - inStart; // 左子树长度(节点个数)
        int right = inEnd - index; // 右子树长度(节点个数)
        // 找左子树的根节点 
        ans->left = buid(preorder, inorder, preStart + 1, preStart + left, inStart, index - 1);
        // 找右子树的根节点
        ans->right = buid(preorder, inorder, preStart + left + 1, preEnd, index + 1, inEnd);
        return ans;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        for(int i = 0;i < inorder.size();i++){
            mp[inorder[i]] = i; // 键值对为 (数据,索引)
        }
        return buid(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1);
    }
};

后序 + 中序 → 构造

class Solution {
public:
    unordered_map<int, int> mp;// 记录每个节点在中序遍历中的索引
    TreeNode* buid(const vector<int>& postorder, const vector<int>& inorder,
        int postStart, int postEnd, int inStart, int inEnd){
        // 后序、中序的起始节点作为参数
        if(postStart > postEnd) return nullptr;
        int root = postorder[postEnd]; // 后序的最后一个节点就是整个二叉树的根节点
        int index = mp[root]; // 获取根节点在中序遍历中的位置

        TreeNode* ans = new TreeNode(root); // 创建根节点
        int left = index - inStart; // 左子树长度(节点个数)
        int right = inEnd - index; // 右子树长度(节点个数)
        // 找左子树的根节点 
        ans->left = buid(postorder, inorder, postStart, postStart + left - 1, inStart, index - 1);
        // 找右子树的根节点
        ans->right = buid(postorder, inorder, postStart + left, postEnd - 1, index + 1, inEnd);
        return ans;
    }
    TreeNode* buildTree(vector<int>& postorder, vector<int>& inorder) {
        for(int i = 0;i < inorder.size();i++){
            mp[inorder[i]] = i; // 键值对为 (数据,索引)
        }
        return buid(postorder, inorder, 0, postorder.size() - 1, 0, inorder.size() - 1);
    }
};

108. 将有序数组转换为二叉搜索树

/**
 * 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:
    // 把数组 [left, right - 1] 转成平衡二叉搜索树
    TreeNode* dfs(vector<int>& nums, int left, int right){
        if(left == right) return nullptr;
        int mid = (left + right) / 2; // 取中间值做根节点
        return new TreeNode(nums[mid], dfs(nums, left, mid), dfs(nums, mid + 1, right));
    }
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        // 二叉搜索树:小的放左节点,大的放右节点
        // 平衡 二叉搜索树:取有序数组的中位数做根节点
        return dfs(nums, 0, nums.size());
    }
};

动态规划

198. 打家劫舍【线性DP】

image

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 0) return 0;
        // f(k) = 偷 [0, k-1] 房间中的最大金额
        // f(0) = 0, f(1) = nums[0]
        // f(k) = max{ rob(k-1), nums[k-1] + rob(k-2) }
        vector<int> dp;
        dp.push_back(0);
        dp.push_back(nums[0]);
        for(int i = 2;i <= nums.size();i++){
            dp.push_back(max(dp[i - 1], dp[i - 2] + nums[i - 1]));
        }
        return dp[nums.size()];
    }
};

可以直接定义dp数组大小,并初始化为0。

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 0) return 0;
        // f(k) = 偷 [0, k-1] 房间中的最大金额
        // f(0) = 0, f(1) = nums[0]
        // f(k) = max{ rob(k-1), nums[k-1] + rob(k-2) }
        int n = nums.size();
        vector<int> dp(n + 1, 0);
        dp[0] = 0;
        dp[1] = nums[0];
        for(int i = 2;i <= nums.size();i++){
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1]);
        }
        return dp[n];
    }
};

53. 最大子数组和

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        vector<int> dp(nums.size());
        dp[0] = nums[0];
        for(int i = 1;i < nums.size();i++){
            dp[i] = max(dp[i - 1], 0) + nums[i];// 要么就前半部分加上自己,要么只要自己
        }
        int ans = -1e9;
        for(int x : dp) ans = max(ans, x);
        return ans;
    }
};

152. 乘积最大子数组

维护两个dp数组,一个是最大值,一个是最小值,因为有负负得正的可能,所以最小的数乘以一个负数可能得到最大的数,所以需要记录一个dp_min。

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        vector<int> dp_max(nums.size()), dp_min(nums.size());
        dp_max[0] = nums[0], dp_min[0] = nums[0];
        for(int i = 1;i < nums.size();i++){
            int x = nums[i];
            dp_max[i] = max({dp_max[i - 1] * x, dp_min[i - 1] * x, x});
            dp_min[i] = min({dp_max[i - 1] * x, dp_min[i - 1] * x, x});
        }
        int ans = -1e9;
        for(int x : dp_max) ans = max(ans, x);
        return ans;
    }
};

补充题目

求二叉树第K层的度不为1的结点个数

#include <iostream>
#include <queue>
using namespace std;

struct TreeNode{
	char val;
	TreeNode * left, * right;
	TreeNode(char c){
		val = c;
		left = NULL;
		right = NULL;
	}
};

int count(TreeNode * root, int k){
	if(root == NULL) return 0;
	queue<TreeNode*> q;
	q.push(root);
	int level = 1;
	int ans = 0;
	while(!q.empty()){
		int n = q.size();
		if(level < k){
			for(int i = 0;i < n;i++){
				TreeNode* t = q.front();
				q.pop();
				if(t->left != NULL) q.push(t->left);
				if(t->right != NULL) q.push(t->right);
			}
			level++;
		}else if(k == level){
			for(int i = 0;i < n;i++){
				TreeNode* t = q.front();
				q.pop();
				int x = 0;
				if(t->left != NULL) x++;
				if(t->right != NULL) x++;
				if(x != 1) ans++;
			}
			return ans;
		}
	}
	return 0;
}

int main() {
	// 构造二叉树
    TreeNode* root = new TreeNode('A');

    root->left = new TreeNode('B');
    root->right = new TreeNode('C');

    root->left->left = new TreeNode('D');
    root->left->right = new TreeNode('E');

    root->right->right = new TreeNode('F');

    root->left->right->left = new TreeNode('G');
    cout << count(root,3);
    return 0;
}
posted @ 2026-09-01 12:25  idle_life  阅读(9)  评论(0)    收藏  举报