Leetcode 刷题总结——树

1. 二叉树的中序遍历(非递归版)

点我
/**
 * 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> res;
        inOrder(root, res);
        return res;
    }

    void inOrder(TreeNode* root, vector<int>& res){
        // 使用栈
        stack<TreeNode*> st;
        TreeNode *p = root;

        while(p || !st.empty()){
            if(p){
                st.push(p);
                p = p->left;
            }
            else{
                TreeNode *node = st.top();
                st.pop();
                res.push_back(node->val);
                p = node->right;
            }
        }
    }
};

2. 二叉树的前序遍历(非递归版)

点我
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        // 原来是已经建好树了
        vector<int> res;
        stack<TreeNode*> st;
        TreeNode* p = root;

        while(p || !st.empty()){
            if(p){
                st.push(p);
                // 访问p
                res.push_back(p->val);
                p = p->left;
            }
            else{
                // 弹栈,访问右孩子
                p = st.top();
                st.pop();
                p = p->right;
            }
        }

        return res;
    }
};

3. 二叉树的后序遍历(非递归版)

点我
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        TreeNode* p = root;
        stack<TreeNode*> st;
        TreeNode* r = nullptr;

        while(p || !st.empty()){
            if(p){
                st.push(p);
                p = p->left;
            }
            else{
                // 需要左右孩子都访问完成,才能弹栈
                // 此时左孩子已经访问完成
                // 检查是否有右孩子,要记录是否访问过右孩子
                // 只需要记下上次访问的结点就可以
                p = st.top();
                if(p->right && p->right != r){
                    p = p->right;
                }else{
                    // 弹栈访问
                    p = st.top();
                    st.pop();
                    res.push_back(p->val);
                    r = p;
                    p = nullptr;  // 每次访问完一个节点,相当于遍历完以该节点为根的子树
                }
            }
        }
        return res;
    }
};

4. 比较两棵树是否相同

注意节点的值并不是两两不同,因此不能使用前序+中序序列相同来判断。
其实关于树的题目,一个很自然的思路就是 递归!

点我
class Solution {
public:

    // 很自然的想法是递归,枯了
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(!p && !q) return true;
        if(!p || !q) return false;

        if(p->val == q->val)
            return (isSameTree(p->left, q->left) && isSameTree(p->right, q->right));
        else
            return false;
    }

};

5. 对称二叉树

要梳理好思路,找到可以递归的点在哪里。
现将 评论区haventmetyou大佬的指点 总结如下:
一棵树是否对称→左树、右树是否对称→左树左孩、右树右孩是否对称 && 左树右孩、右树左孩是否对称(此时句法结构已经体现出递归的解决思路了)。
其实还有迭代版本~(后续补)
下面是我自己的实现:

点我
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(!root) return true;
        return leftRightSymmetric(root->left, root->right);
    }

    bool leftRightSymmetric(TreeNode* p, TreeNode* q){
        if(!p && !q) return true;
        if(!p || !q) return false;

        if(p->val == q->val)
            return leftRightSymmetric(p->left, q->right) && leftRightSymmetric(p->right, q->left);       
        else
            return false;
    }   
};

6. 将有序数组转换为二叉树

已知中序序列,建立一棵平衡二叉树。递归找根。

点我
class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return buildBalancedTreeByInOrderSequence(nums, 0, nums.size()-1);
    }

    TreeNode* buildBalancedTreeByInOrderSequence(vector<int>& nums, int start, int end){
        if(start <= end){
            int mid = (start+end) / 2;  // 闭区间
            int rootVal = nums[mid];
            TreeNode* p = new TreeNode(rootVal);

            p->left = buildBalancedTreeByInOrderSequence(nums, start, mid - 1); 
            p->right = buildBalancedTreeByInOrderSequence(nums, mid + 1, end);

            return p;
        }
        else
            return nullptr;
    }
};

7. 二叉树的最小深度

深搜。

点我
class Solution {
public:
    int minDepth(TreeNode* root) {
        if(root == nullptr) return 0;

        if(root->left == nullptr) return minDepth(root->right) + 1;
        if(root->right == nullptr) return minDepth(root->left) + 1;
        return min(minDepth(root->left), minDepth(root->right)) + 1;
    }
};

8. 路径总和

点我
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr){
            return false;
        }

        return pathcount(root, targetSum);	//这个位置写得略冗余
    }

    bool pathcount(TreeNode* root, int targetSum){
        //当前节点是叶子节点
        if(root->left == nullptr && root->right == nullptr && targetSum == root->val){
            return true;
        }
        else{
            bool leftExist = false, rightExist = false;
            if(root->left)
                leftExist = pathcount(root->left, targetSum - root->val);
            if(root->right)
                rightExist = pathcount(root->right, targetSum - root->val);
            return leftExist || rightExist;
        }
    }

};

9. 翻转二叉树

对于每个节点,翻转其左右子树。

点我
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr) return nullptr;
        // 对于一个节点,他的左子树和右子树都要翻转
        TreeNode* left = nullptr, *right = nullptr;
        if(root->left)
            left = invertTree(root->left);
        if(root->right)
            right = invertTree(root->right);
        // 交换左右子树
        root->left = right;
        root->right = left;
        
        return root;
    }
};
posted @ 2022-03-16 17:16  seamoon  阅读(32)  评论(0)    收藏  举报