一刷代码随想录——二叉树

news2024/12/28 5:39:47
    • 理论基础

【1】分类

  • 满二叉树

  • 完全二叉树

优先级队列其实是一个堆,堆就是一棵完全二叉树,同时保证父子节点的顺序关系。

  • 二叉搜素树

二叉搜索树是有数值的,二叉搜索树是一个有序树

  • 平衡二叉搜素树(AVL)

C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn,注意我这里没有说unordered_map、unordered_set,unordered_map、unordered_map底层实现是哈希表。

【2】存储方式

(1)链式存储

(2)顺序存储

如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。

【3】定义

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

【4】遍历

a.深度优先遍历:先往深走,遇到叶子节点再往回走。

  • 前序遍历(递归法,迭代法)

  • 中序遍历(递归法,迭代法)

  • 后序遍历(递归法,迭代法)

b.广度优先遍历:一层一层的去遍历。

  • 层次遍历(迭代法)

之前我们讲栈与队列的时候,就说过栈其实就是递归的一种实现结构,也就说前中后序遍历的逻辑其实都是可以借助栈使用非递归的方式来实现的。

而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。

2.深度优先遍历

【1】二叉树的前序遍历144

(1)递归

class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        vec.push_back(cur->val);    // 中
        traversal(cur->left, vec);  // 左
        traversal(cur->right, vec); // 右
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> re;
        traversal(root, re);
        return re;
    }
};

(2)迭代

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>re;
        stack<TreeNode*>st;       
        if (!root) return re;
        st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            st.pop();
            re.push_back(tmp->val);
            if (tmp->right) st.push(tmp->right);
            if (tmp->left) st.push(tmp->left);
        }
        return re;
    }
};

(3)统一迭代

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int>re;
        stack<TreeNode*>st;
        if (root) st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            if (tmp) {
                st.pop();
                if (tmp->right) st.push(tmp->right);
                if (tmp->left) st.push(tmp->left);
                st.push(tmp);
                st.push(NULL);
            }
            else {
                st.pop();
                tmp = st.top();
                st.pop();
                re.push_back(tmp->val);
            }
        }
        return re;
    }
};

【2】二叉树的中序遍历94

(1)递归

class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;        
        traversal(cur->left, vec);  // 左
        vec.push_back(cur->val);    // 中
        traversal(cur->right, vec); // 右
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>re;
        traversal(root, re);
        return re;
    }
};

(2)迭代

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>re;
        stack<TreeNode*>st;
        if (!root) return re;
        TreeNode* cur = root;
        while (cur || !st.empty()) {
            if (cur) {
                st.push(cur);
                cur = cur->left;
            }
            else {
                cur = st.top();
                st.pop();
                re.push_back(cur->val);
                cur = cur->right;
            }
        }
        return re;
    }
};

(3)统一迭代

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>re;
        stack<TreeNode*>st;
        if (root) st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            if (tmp) {
                st.pop();
                if (tmp->right) st.push(tmp->right);
                st.push(tmp);
                st.push(NULL);
                if (tmp->left) st.push(tmp->left);                              
            }
            else {
                st.pop();
                tmp = st.top();
                st.pop();
                re.push_back(tmp->val);
            }
        }
        return re;
    }
};

【3】二叉树的后序遍历145

(1)递归

class Solution {
public:
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;        
        traversal(cur->left, vec);  // 左
        traversal(cur->right, vec); // 右
        vec.push_back(cur->val);    // 中        
    }
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>re;
        traversal(root, re);
        return re;
    }
};

(2)迭代

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>re;
        stack<TreeNode*>st;
        if (!root) return re;
        st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            st.pop();
            re.push_back(tmp->val);           
            if (tmp->left) st.push(tmp->left);
            if (tmp->right) st.push(tmp->right);
        }
        reverse(re.begin(),re.end());
        return re;
    }
};

(3)统一迭代

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>re;
        stack<TreeNode*>st;
        if (root) st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            if (tmp) {
                st.pop();                
                st.push(tmp);
                st.push(NULL);
                if (tmp->right) st.push(tmp->right);
                if (tmp->left) st.push(tmp->left);
            }
            else {
                st.pop();
                tmp = st.top();
                st.pop();
                re.push_back(tmp->val);
            }
        }
        return re;
    }
};

【4】前中后序遍历总结:

【5】左子叶之和404

递归

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;
        int leftValue = 0;
        if (root->left != NULL && root->left->left == NULL && root->left->right == NULL) 
            leftValue = root->left->val;
        
        return leftValue + sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
    }
};

迭代

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        stack<TreeNode*> st;
        if (root == NULL) return 0;
        st.push(root);
        int result = 0;
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            if (node->left != NULL && node->left->left == NULL && node->left->right == NULL)
                result += node->left->val;
            //先左或者先右都可以
            if (node->left) st.push(node->left);
            if (node->right) st.push(node->right);          
        }
        return result;
    }
};

3.广度优先遍历

【1】二叉树的层序遍历102

递归

class Solution {
public:
    void traversal(TreeNode* cur, vector<vector<int>>& re, int depth) {
        if (!cur) return;
        if (re.size() == depth) re.push_back(vector<int>());
        re[depth].push_back(cur->val);
        traversal(cur->left, re, depth + 1);
        traversal(cur->right, re, depth + 1);
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> re;
        int depth = 0;
        traversal(root, re, depth);
        return re;
    }
};

迭代

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

【2】二叉树的层序遍历II 107

题目描述:

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

输入:root = [3,9,20,null,null,15,7]

输出:[[15,7],[9,20],[3]]

在return之前加如下一行:

reverse(re.begin(), re.end()); // 在这里反转一下数组即可

【3】二叉树的右视图199

题目描述:

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

层序遍历中,只记录每一行的最后一个值

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

【4】二叉树的层平均值637

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        queue<TreeNode*>que;
        vector<double> re;
        if (root) que.push(root);
        while (!que.empty()) {
            double sum = 0.0;
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                TreeNode* tmp = que.front();
                que.pop();
                sum += (double)tmp->val;
                if (tmp->left) que.push(tmp->left);
                if (tmp->right) que.push(tmp->right);
            }            
            re.push_back(sum/size);            
        }
        return re;
    }
};

【5】N叉树的层序遍历429

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        queue<Node*>que;
        vector<vector<int>> re;
        if (root) que.push(root);
        while (!que.empty()) {
            vector<int>vec;
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                Node* tmp = que.front();
                que.pop();
                vec.push_back(tmp->val);
                for (int j = 0; j < tmp->children.size(); ++j) {
                    if (tmp->children[j]) que.push(tmp->children[j]);
                }               
            }
            re.push_back(vec);
        }
        return re;
    }
};

【6】在每个树行中找最大值515

class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        queue<TreeNode*>que;
        vector<int> re;
        if (root) que.push(root);
        while (!que.empty()) {
            int max = INT32_MIN;
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                TreeNode* tmp = que.front();
                que.pop();
                max = max > tmp->val ? max : tmp->val;
                if (tmp->left) que.push(tmp->left);
                if (tmp->right) que.push(tmp->right);
            }
            re.push_back(max);
        }
        return re;
    }
};

【7】找树左下角的值513

递归

class Solution {
public:
    int maxLen = INT_MIN;
    int maxleftValue;
    void traversal(TreeNode* root, int leftLen) {
        if (root->left == NULL && root->right == NULL) {
            if (leftLen > maxLen) {
                maxLen = leftLen;
                maxleftValue = root->val;
            }
            return;
        }
        if (root->left) {
            traversal(root->left, leftLen + 1); // 隐藏着回溯
        }
        if (root->right) {
            traversal(root->right, leftLen + 1); // 隐藏着回溯
        }
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        traversal(root, 0);
        return maxleftValue;
    }
};

层序+记录每行首节点

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

(不彻底)翻转+层序

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

【8】填充每个节点的下一个右侧节点指针116/117

区别:完美二叉树

单独记录i==0的节点

class Solution {
public:
    Node* connect(Node* root) {
        queue<Node*>que;        
        if (root) que.push(root);
        while (!que.empty()) {           
            int size = que.size();
            Node* pre;
            Node* node;
            for (int i = 0; i < size; ++i) {
                if (i == 0) {
                    pre = que.front();
                    que.pop();
                    node = pre;
                }
                else {
                    node = que.front();
                    que.pop();
                    pre->next = node;
                    pre = pre->next;
                }
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }           
        }
        return root;
    }
};

【9】二叉树的最大深度104

层序

class Solution {
public:
    int maxDepth(TreeNode* root) {
        queue<TreeNode*>que;
        int depth = 0;
        if (root) que.push(root);
        while (!que.empty()) {           
            int size = que.size();
            depth++;
            for (int i = 0; i < size; ++i) {
                TreeNode* tmp = que.front();
                que.pop();               
                if (tmp->left) que.push(tmp->left);
                if (tmp->right) que.push(tmp->right);
            }                                  
        }
        return depth;
    }
};

前序+回溯

class Solution {
public:
    int re;
    void getdepth(TreeNode* node, int depth) {
        re = depth > re ? depth : re;
        if (!node->left && !node->right) return;
        if (node->left) {
            depth++;
            getdepth(node->left, depth);
            depth--;
        }
        if (node->right) {
            depth++;
            getdepth(node->right, depth);
            depth--;
        }       
    }
    
    int maxDepth(TreeNode* root) {
        re = 0;
        if (!root) return re;
        getdepth(root, 1);
        return re;
    }
};

【10】二叉树的最小深度111

class Solution {
public:
    int minDepth(TreeNode* root) {
        queue<TreeNode*>que;
        int depth = 0;
        if (root) que.push(root);
        while (!que.empty()) {
            int size = que.size();
            depth++;
            for (int i = 0; i < size; ++i) {
                TreeNode* tmp = que.front();
                que.pop();
                if (tmp->left) que.push(tmp->left);
                if (tmp->right) que.push(tmp->right);
                if (!tmp->left && !tmp->right) return depth;
            }            
        }
        return depth;
    }
};

【11】N叉树的最大深度559

class Solution {
public:
    int maxDepth(Node* root) {
        queue<Node*>que;        
        int depth = 0;
        if (root) que.push(root);
        while (!que.empty()) {           
            depth++;
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                Node* tmp = que.front();
                que.pop();               
                for (int j = 0; j < tmp->children.size(); ++j) {
                    if (tmp->children[j]) que.push(tmp->children[j]);
                }
            }            
        }
        return depth;
    }
};

【12】完全二叉树的节点个数222

递归

class Solution {
private:
    int getNodesNum(TreeNode* cur) {
        if (cur == 0) return 0;
        int leftNum = getNodesNum(cur->left);     
        int rightNum = getNodesNum(cur->right);    
        int treeNum = leftNum + rightNum + 1;      
        return treeNum;
    }
public:
    int countNodes(TreeNode* root) {
        return getNodesNum(root);
    }
};

递归简化

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == NULL) return 0;
        return 1 + countNodes(root->left) + countNodes(root->right);
    }
};

层序

class Solution {
public:
    int countNodes(TreeNode* root) {
        queue<TreeNode*>que;
        int sum = 0;
        if (root) que.push(root);
        while (!que.empty()) {           
            int size = que.size();
            sum += size;
            for (int i = 0; i < size; ++i) {
                TreeNode* tmp = que.front();
                que.pop();               
                if (tmp->left) que.push(tmp->left);
                if (tmp->right) que.push(tmp->right);
            }
        }
        return sum;
    }
};

完全二叉树

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr) return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftHeight = 0, rightHeight = 0; 
        while (left) { 
            left = left->left;
            leftHeight++;
        }
        while (right) { 
            right = right->right;
            rightHeight++;
        }
        if (leftHeight == rightHeight) {
            // (2<<1) 相当于2^2,所以leftHeight初始为0
            return (2 << leftHeight) - 1;
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

4.二叉树操作

【1】翻转二叉树226

【1】递归

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (!root) return root;
        swap(root->left, root->right);  
        invertTree(root->left);         
        invertTree(root->right);        
        return root;
    }
};

【2】递归中序

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        invertTree(root->left);         
        swap(root->left, root->right);  
        //依然要遍历左孩子,因为中间节点已经翻转
        invertTree(root->left);
        return root;
    }
};

【3】层序

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        queue<TreeNode*>que;       
        if (root) que.push(root);
        while (!que.empty()) {
            
            int size = que.size();
            for (int i = 0; i < size; ++i) {
                TreeNode* tmp = que.front();
                que.pop();
                swap(tmp->left, tmp->right);
                if (tmp->left) que.push(tmp->left);
                if (tmp->right) que.push(tmp->right);
            }            
        }
        return root;
    }
};

【4】前序

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {        
        stack<TreeNode*>st;       
        if (!root) return root;
        st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            st.pop();
            swap(tmp->left, tmp->right);
            if (tmp->right) st.push(tmp->right);
            if (tmp->left) st.push(tmp->left);
        }
        return root;
    }
};

【5】前序统一

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {        
        stack<TreeNode*>st;
        if (root) st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            if (tmp) {
                st.pop();                
                swap(tmp->left, tmp->right);
                if (tmp->right) st.push(tmp->right);
                if (tmp->left) st.push(tmp->left);
                st.push(tmp);
                st.push(NULL);
            }
            else {
                st.pop();
                tmp = st.top();
                st.pop();                              
            }
        }
        return root;
    }
};

【6】深度统一通法

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {        
        stack<TreeNode*>st;
        if (root) st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            if (tmp) {
                st.pop();                
                if (tmp->right) st.push(tmp->right);
                if (tmp->left) st.push(tmp->left);
                st.push(tmp);
                st.push(NULL);
            }
            else {
                st.pop();
                tmp = st.top();
                st.pop();     
//difference           
                swap(tmp->left, tmp->right);
            }
        }
        return root;
    }
};

【2】对称二叉树II 101

【1】层序

带null的层序遍历,判断每一层的vector是否对称

【2】递归

class Solution {
public:
    bool compare(TreeNode* left, TreeNode* right) {       
        if (left == NULL && right != NULL) return false;
        else if (left != NULL && right == NULL) return false;
        else if (left == NULL && right == NULL) return true;        
        else if (left->val != right->val) return false;

        // 左右节点都不为空,且数值相同
        bool outside = compare(left->left, right->right);
        bool inside = compare(left->right, right->left);    
        bool isSame = outside && inside;                    
        return isSame;
    }

    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        return compare(root->left, root->right);
    }
};

【3】迭代队列

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        queue<TreeNode*> que;
        que.push(root->left);  
        que.push(root->right);  

        while (!que.empty()) {  
            TreeNode* leftNode = que.front(); que.pop();
            TreeNode* rightNode = que.front(); que.pop();
            // 左右都空,对称
            if (!leftNode && !rightNode)  continue;
            // 左右一个节点不为空,或者都不为空但数值不相同,返回false
            if ((!leftNode || !rightNode || (leftNode->val != rightNode->val)))
                return false;

            que.push(leftNode->left);   
            que.push(rightNode->right); 
            que.push(leftNode->right);  
            que.push(rightNode->left); 
        }
        return true;
    }
};

【4】迭代栈

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (!root) return true;
        stack<TreeNode*> st;
        st.push(root->left);
        st.push(root->right);

        while (!st.empty()) {
            TreeNode* leftNode = st.top(); st.pop();
            TreeNode* rightNode = st.top(); st.pop();
            if (!leftNode && !rightNode) continue;
            if ((!leftNode || !rightNode || (leftNode->val != rightNode->val)))
                return false;

            st.push(leftNode->left);
            st.push(rightNode->right);
            st.push(leftNode->right);
            st.push(rightNode->left);
        }
        return true;
    }
};

【3】平衡二叉树110

递归

class Solution {
public:
    int getHeight(TreeNode* node) {
        if (node == NULL)    return 0;

        int leftHeight = getHeight(node->left);
        if (leftHeight == -1) return -1;
        int rightHeight = getHeight(node->right);
        if (rightHeight == -1) return -1;
        return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
    }
    bool isBalanced(TreeNode* root) {
        return getHeight(root) == -1 ? false : true;
    }
};

迭代

class Solution {
public:
    int getdepth(TreeNode* cur) {
        stack<TreeNode*>st;
        if (cur) st.push(cur);
        int depth = 0;
        int re = 0;
        //后序统一
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            if (tmp) {
                st.pop();
                st.push(tmp);
                st.push(NULL);
                if (tmp->right) st.push(tmp->right);
                if (tmp->left) st.push(tmp->left);
                depth++;
            }
            else {
                st.pop();
                tmp = st.top();
                st.pop();
                depth--;
            }
            re = re > depth ? re : depth;
        }
        return re;
    }

    bool isBalanced(TreeNode* root) {
        stack<TreeNode*>st;
        if (!root) return true;
        st.push(root);
        while (!st.empty()) {
            TreeNode* tmp = st.top();
            st.pop();
            if (abs(getdepth(tmp->left) - getdepth(tmp->right)) > 1)
                return false;
            if (tmp->right) st.push(tmp->right);
            if (tmp->left) st.push(tmp->left);
        }
        return true;
    }
};

110和104的getdepth函数可以互相转化

5.二叉树路径

【1】二叉树的所有路径257

递归+回溯

class Solution {
private:
    void traversal(TreeNode* cur, vector<int>& path, vector<string>& result) {
        path.push_back(cur->val);
        if (cur->left == NULL && cur->right == NULL) {
            string sPath;
            for (int i = 0; i < path.size() - 1; i++) {
                sPath += to_string(path[i]);
                sPath += "->";
            }
            sPath += to_string(path[path.size() - 1]);
            result.push_back(sPath);
            return;
        }
        if (cur->left) {
            traversal(cur->left, path, result);
            path.pop_back(); // 回溯
        }
        if (cur->right) {
            traversal(cur->right, path, result);
            path.pop_back(); // 回溯
        }
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        vector<int> path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;
    }
};

递归

class Solution {
private:

    void traversal(TreeNode* cur, string path, vector<string>& result) {
        path += to_string(cur->val); // 中
        if (cur->left == NULL && cur->right == NULL) {
            result.push_back(path);
            return;
        }
        if (cur->left) traversal(cur->left, path + "->", result); // 左
        if (cur->right) traversal(cur->right, path + "->", result); // 右
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        string path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;

    }
};

迭代

class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        stack<TreeNode*> treeSt;
        stack<string> pathSt;   
        vector<string> result; 
        if (root == NULL) return result;
        treeSt.push(root);
        pathSt.push(to_string(root->val));
        while (!treeSt.empty()) {
            TreeNode* node = treeSt.top(); treeSt.pop(); 
            string path = pathSt.top(); pathSt.pop();   
            if (node->left == NULL && node->right == NULL) { 
                result.push_back(path);
            }
            if (node->right) {
                treeSt.push(node->right);
                pathSt.push(path + "->" + to_string(node->right->val));
            }
            if (node->left) {
                treeSt.push(node->left);
                pathSt.push(path + "->" + to_string(node->left->val));
            }
        }
        return result;
    }
};

【2】路径总和112

题目描述:

判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。

递归

class Solution {
public:
     bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) return false;
        if (!root->left && !root->right && targetSum == root->val) return true;             
        return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
    }
};

迭代

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) return false;       
        stack<pair<TreeNode*, int>> st;
        st.push(pair<TreeNode*, int>(root, root->val));
        while (!st.empty()) {
            pair<TreeNode*, int> node = st.top();
            st.pop();
            
            if (!node.first->left && !node.first->right && targetSum == node.second) return true;
           
            if (node.first->right) {
                st.push(pair<TreeNode*, int>(node.first->right, node.second + node.first->right->val));
            }
           
            if (node.first->left) {
                st.push(pair<TreeNode*, int>(node.first->left, node.second + node.first->left->val));
            }
        }
        return false;
    }
};

【3】路径总和II 113

题目描述:

找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    // 递归函数不需要返回值,因为我们要遍历整个树
    void traversal(TreeNode* cur, int count) {
        if (!cur->left && !cur->right && count == 0) { // 遇到了叶子节点且找到了和为targetSum的路径
            result.push_back(path);
            return;
        }

        if (!cur->left && !cur->right) return ; // 遇到叶子节点而没有找到合适的边,直接返回

        if (cur->left) { // 左 (空节点不遍历)
            path.push_back(cur->left->val);
            count -= cur->left->val;
            traversal(cur->left, count);    // 递归
            count += cur->left->val;        // 回溯
            path.pop_back();                // 回溯
        }
        if (cur->right) { // 右 (空节点不遍历)
            path.push_back(cur->right->val);
            count -= cur->right->val;
            traversal(cur->right, count);   // 递归
            count += cur->right->val;       // 回溯
            path.pop_back();                // 回溯
        }
        return ;
    }

public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        result.clear();
        path.clear();
        if (root == nullptr) return result;
        path.push_back(root->val); // 把根节点放进路径
        traversal(root, targetSum - root->val);
        return result;
    }
};

6.构造二叉树

【1】从中序与后序遍历序列构造二叉树106

题目描述:

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

class Solution {
private:
    // 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
    TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
        if (postorderBegin == postorderEnd) return NULL;

        int rootValue = postorder[postorderEnd - 1];
        TreeNode* root = new TreeNode(rootValue);

        if (postorderEnd - postorderBegin == 1) return root;

        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        // 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        // 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;

        // 切割后序数组
        // 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
        int leftPostorderBegin =  postorderBegin;
        int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin; // 终止位置是 需要加上 中序区间的大小size
        // 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
        int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
        int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了

        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  postorder, leftPostorderBegin, leftPostorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);

        return root;
    }
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        // 左闭右开的原则
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

【2】从前序与中序遍历序列构造二叉树105

class Solution {
private:
        TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
        if (preorderBegin == preorderEnd) return NULL;

        int rootValue = preorder[preorderBegin]; // 注意用preorderBegin 不要用0
        TreeNode* root = new TreeNode(rootValue);

        if (preorderEnd - preorderBegin == 1) return root;

        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        // 中序左区间,左闭右开[leftInorderBegin, leftInorderEnd)
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        // 中序右区间,左闭右开[rightInorderBegin, rightInorderEnd)
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;

        // 切割前序数组
        // 前序左区间,左闭右开[leftPreorderBegin, leftPreorderEnd)
        int leftPreorderBegin =  preorderBegin + 1;
        int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; // 终止位置是起始位置加上中序左区间的大小size
        // 前序右区间, 左闭右开[rightPreorderBegin, rightPreorderEnd)
        int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
        int rightPreorderEnd = preorderEnd;

        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  preorder, leftPreorderBegin, leftPreorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);

        return root;
    }

public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (inorder.size() == 0 || preorder.size() == 0) return NULL;

        // 参数坚持左闭右开的原则
        return traversal(inorder, 0, inorder.size(), preorder, 0, preorder.size());
    }
};

前序和中序可以唯一确定一颗二叉树。

后序和中序可以唯一确定一颗二叉树。

那么前序和后序可不可以唯一确定一颗二叉树呢?

前序和后序不能唯一确定一颗二叉树!,因为没有中序遍历无法确定左右部分,也就是无法分割。

【3】最大二叉树654

题目描述:

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

创建一个根节点,其值为 nums 中的最大值。

递归地在最大值 左边 的 子数组前缀上 构建左子树。

递归地在最大值 右边 的 子数组后缀上 构建右子树。

返回 nums 构建的 最大二叉树 。

class Solution {
private:
    // 在左闭右开区间[left, right),构造二叉树
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        if (left >= right) return nullptr;

        // 分割点下标:maxValueIndex
        int maxValueIndex = left;
        for (int i = left + 1; i < right; ++i) {
            if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;
        }

        TreeNode* root = new TreeNode(nums[maxValueIndex]);

        // 左闭右开:[left, maxValueIndex)
        root->left = traversal(nums, left, maxValueIndex);

        // 左闭右开:[maxValueIndex + 1, right)
        root->right = traversal(nums, maxValueIndex + 1, right);

        return root;
    }
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return traversal(nums, 0, nums.size());
    }
};

【4】合并二叉树617

题目描述:

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

前序原树:

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2
        if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1
        // 修改了t1的数值和结构
        t1->val += t2->val;                             // 中
        t1->left = mergeTrees(t1->left, t2->left);      // 左
        t1->right = mergeTrees(t1->right, t2->right);   // 右
        return t1;
    }
};

前序新树:

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2;
        if (t2 == NULL) return t1;
        // 重新定义新的节点,不修改原有两个树的结构
        TreeNode* root = new TreeNode(0);
        root->val = t1->val + t2->val;
        root->left = mergeTrees(t1->left, t2->left);
        root->right = mergeTrees(t1->right, t2->right);
        return root;
    }
};

迭代:

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2;
        if (t2 == NULL) return t1;
        queue<TreeNode*> que;
        que.push(t1);
        que.push(t2);
        while(!que.empty()) {
            TreeNode* node1 = que.front(); que.pop();
            TreeNode* node2 = que.front(); que.pop();
            // 此时两个节点一定不为空,val相加
            node1->val += node2->val;

            // 如果两棵树左节点都不为空,加入队列
            if (node1->left != NULL && node2->left != NULL) {
                que.push(node1->left);
                que.push(node2->left);
            }
            // 如果两棵树右节点都不为空,加入队列
            if (node1->right != NULL && node2->right != NULL) {
                que.push(node1->right);
                que.push(node2->right);
            }

            // 当t1的左节点 为空 t2左节点不为空,就赋值过去
            if (node1->left == NULL && node2->left != NULL) {
                node1->left = node2->left;
            }
            // 当t1的右节点 为空 t2右节点不为空,就赋值过去
            if (node1->right == NULL && node2->right != NULL) {
                node1->right = node2->right;
            }
        }
        return t1;
    }
};

7.二叉搜索树

【1】二叉搜索树中的搜索700

题目描述:

给定二叉搜索树(BST)的根节点 root 和一个整数值 val。

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null

递归:

class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        if (root == NULL || root->val == val) return root;
        if (root->val > val) return searchBST(root->left, val);
        if (root->val < val) return searchBST(root->right, val);
        return NULL;
    }
};

迭代:

class Solution {
public:
    TreeNode* searchBST(TreeNode* root, int val) {
        while (root != NULL) {
            if (root->val > val) root = root->left;
            else if (root->val < val) root = root->right;
            else return root;
        }
        return NULL;
    }
};

【2】验证二叉搜索树98

题目描述:

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 小于 当前节点的数。

节点的右子树只包含 大于 当前节点的数。

所有左子树和右子树自身必须也是二叉搜索树。

递归:

class Solution {
private:
    vector<int> vec;
    void traversal(TreeNode* root) {
        if (root == NULL) return;
        traversal(root->left);
        vec.push_back(root->val); // 将二叉搜索树转换为有序数组
        traversal(root->right);
    }
public:
    bool isValidBST(TreeNode* root) {
        vec.clear(); // 不加这句在leetcode上也可以过,但最好加上
        traversal(root);
        for (int i = 1; i < vec.size(); i++) {
            // 注意要小于等于,搜索树里不能有相同元素
            if (vec[i] <= vec[i - 1]) return false;
        }
        return true;
    }
};

简化递归:

class Solution {
public:
    TreeNode* pre = NULL; // 用来记录前一个节点
    bool isValidBST(TreeNode* root) {
        if (root == NULL) return true;
        bool left = isValidBST(root->left);

        if (pre != NULL && pre->val >= root->val) return false;
        pre = root; // 记录前一个节点

        bool right = isValidBST(root->right);
        return left && right;
    }
};

中序

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        TreeNode* pre = NULL; // 记录前一个节点
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) {
                st.push(cur);
                cur = cur->left;                // 左
            } else {
                cur = st.top();                 // 中
                st.pop();
                if (pre != NULL && cur->val <= pre->val)
                return false;
                pre = cur; //保存前一个访问的结点

                cur = cur->right;               // 右
            }
        }
        return true;
    }
};

【3】二叉搜索树的最小绝对差530

题目描述:

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值

差值是一个正数,其数值等于两值之差的绝对值。

递归

class Solution {
private:
    int result = INT_MAX;
    TreeNode* pre;
    void traversal(TreeNode* cur) {
        if (cur == NULL) return;
        traversal(cur->left);   // 左
        if (pre != NULL)        // 中
            result = min(result, cur->val - pre->val);    
        pre = cur;
        traversal(cur->right);  // 右
    }
public:
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};

中序

class Solution {
public:
    int getMinimumDifference(TreeNode* root) {
        stack<TreeNode*> st;
        int re=INT32_MAX;
        TreeNode* cur = root;
        TreeNode* pre = NULL;
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) {
                st.push(cur);
                cur = cur->left;                // 左
            }
            else {
                cur = st.top();                 // 中
                st.pop();
                if (pre)
                    re = re > (cur->val - pre->val) ? (cur->val - pre->val) : re;
                pre = cur; 
                cur = cur->right;               // 右
            }
        }
        return re;
    }
};

【4】二叉搜索树中的众数501

题目描述:

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

递归:

class Solution {
private:
    int maxCount; // 最大频率
    int count; // 统计频率
    TreeNode* pre;
    vector<int> result;
    void searchBST(TreeNode* cur) {
        if (cur == NULL) return ;

        searchBST(cur->left);       // 左
                                    // 中
        if (pre == NULL) { // 第一个节点
            count = 1;
        } else if (pre->val == cur->val) { // 与前一个节点数值相同
            count++;
        } else { // 与前一个节点数值不同
            count = 1;
        }
        pre = cur; // 更新上一个节点

        if (count == maxCount) { // 如果和最大值相同,放进result中
            result.push_back(cur->val);
        }

        if (count > maxCount) { // 如果计数大于最大值频率
            maxCount = count;   // 更新最大频率
            result.clear();     // 很关键的一步,不要忘记清空result,之前result里的元素都失效了
            result.push_back(cur->val);
        }

        searchBST(cur->right);      // 右
        return ;
    }

public:
    vector<int> findMode(TreeNode* root) {
        count = 0;
        maxCount = 0;
        TreeNode* pre = NULL; // 记录前一个节点
        result.clear();

        searchBST(root);
        return result;
    }
};

迭代

class Solution {
public:
    vector<int> findMode(TreeNode* root) {
        vector<int>re;
        stack<TreeNode*>st;
        int max = 0;
        int cnt = 0;
        TreeNode* cur = root;
        TreeNode* pre = NULL;
        while (cur || !st.empty()) {
            if (cur) {
                st.push(cur);
                cur = cur->left;
            }
            else {
                cur = st.top();
                st.pop();               
                if (!pre) cnt = 1;
                else if (pre->val == cur->val) cnt++;
                else cnt = 1;
                if (max == cnt) re.push_back(cur->val);
                else if (cnt > max) {
                    max = cnt;
                    re.clear();
                    re.push_back(cur->val);
                }
                pre = cur;
                cur = cur->right;
            }
        }
        return re;
    }
};

【5】二叉搜索树的最近公共祖先235

题目描述:

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

递归:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == q || root == p || root == NULL) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if (left != NULL && right != NULL) return root;
        if (left == NULL) return right;
        return left;
    }
};

递归:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root->val > p->val && root->val > q->val) {
            return lowestCommonAncestor(root->left, p, q);
        } else if (root->val < p->val && root->val < q->val) {
            return lowestCommonAncestor(root->right, p, q);
        } else return root;
    }
};

迭代:

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        while(root) {
            if (root->val > p->val && root->val > q->val) {
                root = root->left;
            } else if (root->val < p->val && root->val < q->val) {
                root = root->right;
            } else return root;
        }
        return NULL;
    }
};

【6】二叉树的最近公共祖先236

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == q || root == p || root == NULL) return root;
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        if (left != NULL && right != NULL) return root;
        if (left == NULL) return right;
        return left;
    }
};

【7】二叉搜索树中的插入操作701

递归:

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == NULL) {
            TreeNode* node = new TreeNode(val);
            return node;
        }
        if (root->val > val) root->left = insertIntoBST(root->left, val);
        if (root->val < val) root->right = insertIntoBST(root->right, val);
        return root;
    }
};

递归:

class Solution {
private:
    TreeNode* parent;
    void traversal(TreeNode* cur, int val) {
        if (cur == NULL) {
            TreeNode* node = new TreeNode(val);
            if (val > parent->val) parent->right = node;
            else parent->left = node;
            return;
        }
        parent = cur;
        if (cur->val > val) traversal(cur->left, val);
        if (cur->val < val) traversal(cur->right, val);
        return;
    }

public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        parent = new TreeNode(0);
        if (root == NULL) {
            root = new TreeNode(val);
        }
        traversal(root, val);
        return root;
    }
};

迭代:

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == NULL) {
            TreeNode* node = new TreeNode(val);
            return node;
        }
        TreeNode* cur = root;
        TreeNode* parent = root; // 这个很重要,需要记录上一个节点,否则无法赋值新节点
        while (cur != NULL) {
            parent = cur;
            if (cur->val > val) cur = cur->left;
            else cur = cur->right;
        }
        TreeNode* node = new TreeNode(val);
        if (val < parent->val) parent->left = node;// 此时是用parent节点的进行赋值
        else parent->right = node;
        return root;
    }
};

【8】删除二叉搜索树中的节点450

题目描述:

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

【1】递归:

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) { 
            // 第一种情况:没找到删除的节点,遍历到空节点直接返回了
        if (root == nullptr) return root;
        if (root->val == key) {
            // 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
            if (root->left == nullptr && root->right == nullptr) {
                ///! 内存释放
                delete root;
                return nullptr;
            }
            // 第三种情况:其左孩子空,右孩子不空,删除节点,右孩子补位 ,返回右孩子为根节点
            else if (root->left == nullptr) {
                auto retNode = root->right;
                ///! 内存释放
                delete root;
                return retNode;
            }
            // 第四种情况:其右孩子空,左孩子不空,删除节点,左孩子补位,返回左孩子为根节点
            else if (root->right == nullptr) {
                auto retNode = root->left;
                ///! 内存释放
                delete root;
                return retNode;
            }
            // 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
            // 并返回删除节点右孩子为新的根节点。
            else {
                TreeNode* cur = root->right; // 找右子树最左面的节点
                while(cur->left != nullptr) {
                    cur = cur->left;
                }
                cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置
                TreeNode* tmp = root;   // 把root节点保存一下,下面来删除
                root = root->right;     // 返回旧root的右孩子作为新root
                delete tmp;             // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)
                return root;
            }
        }
        if (root->val > key) root->left = deleteNode(root->left, key);
        if (root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
};

【2】迭代:

class Solution {
private:
    // 将目标节点(删除节点)的左子树放到 目标节点的右子树的最左面节点的左孩子位置上
    // 并返回目标节点右孩子为新的根节点
    // 是动画里模拟的过程
    TreeNode* deleteOneNode(TreeNode* target) {
        if (target == nullptr) return target;
        if (target->right == nullptr) return target->left;
        TreeNode* cur = target->right;
        while (cur->left) {
            cur = cur->left;
        }
        cur->left = target->left;
        return target->right;
    }
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == nullptr) return root;
        TreeNode* cur = root;
        TreeNode* pre = nullptr; // 记录cur的父节点,用来删除cur
        while (cur) {
            if (cur->val == key) break;
            pre = cur;
            if (cur->val > key) cur = cur->left;
            else cur = cur->right;
        }
        if (pre == nullptr) { // 如果搜索树只有头结点
            return deleteOneNode(cur);
        }
        // pre 要知道是删左孩子还是右孩子
        if (pre->left && pre->left->val == key) {
            pre->left = deleteOneNode(cur);
        }
        if (pre->right && pre->right->val == key) {
            pre->right = deleteOneNode(cur);
        }
        return root;
    }
};

【3】普通二叉树:

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == nullptr) return root;
        if (root->val == key) {
            if (root->right == nullptr) { // 这里第二次操作目标值:最终删除的作用
                return root->left;
            }
            TreeNode *cur = root->right;
            while (cur->left) {
                cur = cur->left;
            }
            swap(root->val, cur->val); // 这里第一次操作目标值:交换目标值其右子树最左面节点。
        }
        root->left = deleteNode(root->left, key);
        root->right = deleteNode(root->right, key);
        return root;
    }
};

【9】修剪二叉搜索树669

题目描述:

给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

【1】递归:

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (root == nullptr) return nullptr;
        if (root->val < low) return trimBST(root->right, low, high);
        if (root->val > high) return trimBST(root->left, low, high);
        root->left = trimBST(root->left, low, high);
        root->right = trimBST(root->right, low, high);
        return root;
    }
};

【2】迭代:

class Solution {
public:
    TreeNode* trimBST(TreeNode* root, int L, int R) {
        if (!root) return nullptr;

        // 处理头结点,让root移动到[L, R] 范围内,注意是左闭右闭
        while (root != nullptr && (root->val < L || root->val > R)) {
            if (root->val < L) root = root->right; // 小于L往右走
            else root = root->left; // 大于R往左走
        }
        TreeNode *cur = root;
        // 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
        while (cur != nullptr) {
            while (cur->left && cur->left->val < L) {
                cur->left = cur->left->right;
            }
            cur = cur->left;
        }
        cur = root;

        // 此时root已经在[L, R] 范围内,处理右孩子大于R的情况
        while (cur != nullptr) {
            while (cur->right && cur->right->val > R) {
                cur->right = cur->right->left;
            }
            cur = cur->right;
        }
        return root;
    }
};

【10】将有序数组转换为二叉搜索树108

题目描述:

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足每个节点的左右两个子树的高度差的绝对值不超过 1 的二叉树。

【1】递归:

class Solution {
private:
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        if (left > right) return nullptr;
        int mid = left + ((right - left) / 2);
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = traversal(nums, left, mid - 1);
        root->right = traversal(nums, mid + 1, right);
        return root;
    }
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        TreeNode* root = traversal(nums, 0, nums.size() - 1);
        return root;
    }
};

【2】迭代:

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if (nums.size() == 0) return nullptr;

        TreeNode* root = new TreeNode(0);   // 初始根节点
        queue<TreeNode*> nodeQue;           // 放遍历的节点
        queue<int> leftQue;                 // 保存左区间下标
        queue<int> rightQue;                // 保存右区间下标
        nodeQue.push(root);                 // 根节点入队列
        leftQue.push(0);                    // 0为左区间下标初始位置
        rightQue.push(nums.size() - 1);     // nums.size() - 1为右区间下标初始位置

        while (!nodeQue.empty()) {
            TreeNode* curNode = nodeQue.front();
            nodeQue.pop();
            int left = leftQue.front(); leftQue.pop();
            int right = rightQue.front(); rightQue.pop();
            int mid = left + ((right - left) / 2);

            curNode->val = nums[mid];       // 将mid对应的元素给中间节点

            if (left <= mid - 1) {          // 处理左区间
                curNode->left = new TreeNode(0);
                nodeQue.push(curNode->left);
                leftQue.push(left);
                rightQue.push(mid - 1);
            }

            if (right >= mid + 1) {         // 处理右区间
                curNode->right = new TreeNode(0);
                nodeQue.push(curNode->right);
                leftQue.push(mid + 1);
                rightQue.push(right);
            }
        }
        return root;
    }
};

【11】把二叉搜索树转换为累加树538

题目描述:

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

【1】递归:

class Solution {
private:
    int pre = 0; // 记录前一个节点的数值
    void traversal(TreeNode* cur) { // 右中左遍历
        if (cur == NULL) return;
        traversal(cur->right);
        cur->val += pre;
        pre = cur->val;
        traversal(cur->left);
    }
public:
    TreeNode* convertBST(TreeNode* root) {
        pre = 0;
        traversal(root);
        return root;
    }
};

【2】迭代:

class Solution {
private:
    int pre; // 记录前一个节点的数值
    void traversal(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while (cur != NULL || !st.empty()) {
            if (cur != NULL) {
                st.push(cur);
                cur = cur->right;   // 右
            } else {
                cur = st.top();     // 中
                st.pop();
                cur->val += pre;
                pre = cur->val;
                cur = cur->left;    // 左
            }
        }
    }
public:
    TreeNode* convertBST(TreeNode* root) {
        pre = 0;
        traversal(root);
        return root;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/195796.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Allegro走线规则管理器中网络不会被同步高亮的解决办法

Allegro走线规则管理器中网络不会被同步高亮的解决办法 在用Allegro做PCB设计的时候,在走线的时候,规则管理器中的网络能被高亮起来的话会十分直观,尤其是在做等长设计的时候。 但是有时候会遇到走线的时候,规则管理器中的网络不会同步高亮的情况 如下图: 下面介绍遇到这…

Baklib教您:如何构建有效的帮助中心知识库?

好的帮助中心网站架构良好并精心呈现&#xff0c;使客户可以轻松浏览网站并找到他们要搜索的内容。帮助中心应始终易于搜索&#xff0c;为客户提供品牌知识库的可访问版本&#xff0c;该帮助中心应以用户体验为核心。该站点通常会包含常见问题解答、文章和各种说明&#xff0c;…

SNMP源码分析

源码下载 http://www.net-snmp.org/download.html 源码目录结构 net-snmp程序逻辑 &#xff08;1&#xff09;main主函数 #ifdef WIN32SERVICE //windows系统下使用snmp static int SnmpDaemonMain(int argc, TCHAR * argv[]) #else //linux系统 int main(int argc, char …

吊打面试官,四面拿到阿里、字节 offer 后我还是选择了美团

祸兮福之所倚福兮祸之所伏 上学的时候对这句话不以为然&#xff0c;但是在社会上走的时间越长越觉得有道理 前不久好兄弟和领导闹矛盾裸辞了&#xff0c;身为好兄弟的我总不能干看着吧&#xff0c;总要帮他找工作的。(你们应该不会想我和他一起裸辞吧) 大学的师兄有好几个在大…

西门子200smart与组态王之间无线Profinet通信实例

在实际系统中&#xff0c;车间里分布多台PLC&#xff0c;需要用上位机软件集中控制。通常所有设备距离在几十米到上百米不等。在有通讯需求的时候&#xff0c;如果布线的话&#xff0c;工程量较大且不美观&#xff0c;这种情况下比较适合采用无线通信方式。本方案以组态王和2台…

19 | Rancher 使用介绍(管理 K8s 平台)

目录1 Rancher简介2 Rancher 安装2.1查看k8s的版本2.2 通过 Docker 来进行安装2.3 在 Rancher 的界面上绑定 K8s2.3.1 配置 Kubernetes 集群2.3.2 导入集群2.3.3 集群列表3 Rancher 上部署应用1 Rancher简介 Rancher 提供的功能&#xff1a; 支持 K8s 集群的身份验证和基于角色…

pod内时间时区与宿主机不一致

原因&#xff1a;pod内默认时区是UTC&#xff0c;宿主机时区是CST解决方式&#xff1a;一&#xff0c;如果仅仅是运行一个jar文件&#xff0c;可以使用如下命令&#xff1a;java -jar -Duser.timezoneGMT08 xxx.jar在k8s的Deployment文件中&#xff0c;加入上述JVM启动参数&…

一文读懂I/O模型

什么是IO呢&#xff1f;什么是阻塞非阻塞IO&#xff1f;什么是同步异步IO&#xff1f;什么是IO多路复用&#xff1f;select/epoll跟IO模型有什么关系&#xff1f;有几种经典IO模型呢&#xff1f;BIO、NIO、AIO到底有什么区别的&#xff1f; 如果这些问题&#xff0c;你都能很好…

hjr-微服务(六):如何保障服务稳定性

服务稳定是一个特别大的话题&#xff0c;一般我们用SLA描述服务的质量 SLA一般有99.9 &#xff0c;99.99&#xff0c;就是我们常说的三个9&#xff0c;四个9 有两个纬度衡量 时间纬度 请求纬度 请求的成功率计算方式&#xff1a;SL A 成功请求/&#xff08;成功请求请求失败…

【计算机网络】IP协议

网络层 在复杂的网络环境中寻找一条合适的路径传输数据 IP协议 IP指网际互连协议&#xff0c;Internet Protocol的缩写&#xff0c;是TCP/IP体系中的网络层协议。设计IP的目的是提高网络的可扩展性&#xff1a;一是解决互联网问题&#xff0c;实现大规模、异构网络的互联互通…

【先进设备】仅3mm!超薄款,足底压力步态测量分析系统

产品介绍足底压力步态测量分析系统是一套可用于采集人体足底压力的装置系统&#xff0c;其采用了高密度薄膜压力传感器矩阵&#xff0c;实现足底压力分布数据自动采集和分析&#xff0c;兼具大量程、高采集频率、高精度、高可靠性等特点&#xff0c;可以采集不同疾病的步态及足…

表白生日祝福和3D表白相册

作者&#xff1a;BSXY_19计科_陈永跃BSXY_信息学院注&#xff1a;未经允许禁止转发任何内容表白生日祝福和3D表白相册1、效果与展示2、资源下载3、PC版本生日祝福4、手机版本生日祝福5、动态相册6、如何给别人看1、效果与展示 好友给了我一个链接&#xff0c;我点看一看原来都…

【操作系统】2、进程管理

文章目录二、进程管理2.1 进程、线程的基本概念2.1.1 进程的组成和特性2.1.2 进程的状态和转换2.1.3 进程控制(理解)2.1.4 线程的概念2.1.5 线程的实现方式2.1.5.1 用户级线程2.1.5.2 内核级线程2.1.5.3 多线程模式2.1 6 线程的状态与转换2.2 进程同步2.2.1 概念2.2.2 进程互斥…

gitee通过idea上传新的项目流程

gitee通过idea上传新的项目流程今天开始分享 一、gitee服务端处理 1、登录gitee 服务端&#xff0c;创建仓库 2、点击创建 点击创建 3、创建完成 4、点击复制此仓库的地址&#xff1a;https://gitee.com/nandao1/demo2.git 下面idea会用到 二、idea客户端处理 1、创建demo…

物流行业有什么重要的指标,如何进行数据分析?

大数据是信息时代的典型特征&#xff0c;即通过收集、输入、储存、管理、分析对传统数据进行整合&#xff0c;在互联网的发展中其重要作用。目前大数据已经应用在很多领域中&#xff0c;并影响着各行各业&#xff0c;也有越来越多的行业开始关注大数据&#xff0c;例如“菜鸟网…

C语言数组指针(指向数组的指针)详解

数组&#xff08;Array&#xff09;是一系列具有相同类型的数据的集合&#xff0c;每一份数据叫做一个数组元素&#xff08;Element&#xff09;。数组中的所有元素在内存中是连续排列的&#xff0c;整个数组占用的是一块内存。以int arr[] { 99, 15, 100, 888, 252 };为例&am…

Homekit智能家居DIY-智能触摸面板开关

触摸开关&#xff0c;即通过触摸方式控制的墙壁开关&#xff0c;其感官场景如同我们的触屏手机&#xff0c;只需手指轻轻一点即可达到控制电器的目的&#xff0c;随着人们生活品质的提高&#xff0c;触摸开关将逐渐将换代传统机械按键开关。 触摸开关控制原理 触摸开关我们把…

VL6 多功能数据处理器

一、题目根据指示信号select的不同&#xff0c;对输入信号a,b实现不同的运算。输入信号a,b为8bit有符号数&#xff0c;当select信号为0&#xff0c;输出a&#xff1b;当select信号为1&#xff0c;输出b&#xff1b;当select信号为2&#xff0c;输出ab&#xff1b;当select信号为…

5、排序与分页

文章目录1 排序数据1.1 排序规则1.2 单列排序1.3 多列排序2 分页2.1 背景2.2 实现规则2.3 拓展尚硅谷MySQL数据库教程-讲师&#xff1a;宋红康 我们缺乏的不是知识&#xff0c;而是学而不厌的态度 1 排序数据 1.1 排序规则 使用 ORDER BY 子句排序 ASC&#xff08;ascend&…

MySQL安装教程(windows 64位)详细教程

1.确保电脑为64位系统 2.国外官网下载地址&#xff1a;MySQL : Download MySQL Community Server 2.1.点击下载之后&#xff0c;可以选择注册Oracle账号&#xff0c;也可以跳过直接下载 2.2.国内下载网址&#xff1a;Index of /mysql/MySQL-8.0/ 2.3.下载完成后解压到某一个文…