zoukankan      html  css  js  c++  java
  • LeetCode树专题

    LeetCode树专题

    98. 验证二叉搜索树

    二叉搜索树,每个结点的值都有一个范围

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool isValidBST(TreeNode* root) {
            return dfs(root,INT_MIN,INT_MAX);
        }
        bool dfs(TreeNode* root,long long l,long long  r){
            if(!root) return true; 
            //判断当前结点
            if(root->val < l || root->val > r) return false;
            //递归判断左右子节点
            return dfs(root->left,l,root->val - 1ll) && dfs(root->right,root->val+1ll,r);
        }
    };
    

    94. 二叉树的中序遍历

    二叉树中序遍历的迭代写法

    模拟中序遍历

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> inorderTraversal(TreeNode* root) {
            vector<int> result;
            stack<TreeNode*> stk;
            auto p = root;
            while(p || stk.size()){
                while(p){ //1.把左子树全部加入栈中
                    stk.push(p);
                    p = p->left;
                }
                p = stk.top(); //2.取栈首 输出栈首
                stk.pop();
                result.push_back(p->val);
                p = p->right; //3.转到右子树
            }
            return result;
        }
    };
    

    101. 对称二叉树

    用递归和迭代两种做法

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool isSymmetric(TreeNode* root) {
            if(!root) return true;
            return dfs(root->left,root->right);
        }
        bool dfs(TreeNode* p,TreeNode* q){
            if(!p || !q) return !p && !q; //左右不能一空一不空
            //1.比较当前两结点的值 
    		//2.比较p结点左子树和q结点右子树
    		//3.比较p结点右子树和q结点左子树
            return p->val == q->val && 
    		dfs(p->left,q->right) && dfs(p->right,q->left); 
        }
    };
    

    迭代:左边左中右,右边右中左;每次遍历对应两个结点比较值是否相等

    类似LeetCode94的迭代遍历二叉树的思路

    105. 从前序与中序遍历序列构造二叉树

    假设树中没有重复的元素。
    根据一棵树的前序遍历与中序遍历构造二叉树。

    前序序列确定根

    在中序序列中找到根的值,那么根左边为左子树序列,右边为右子树序列

    前序序列下一个结点是左子树的根;

    前序序列当前位置加上左子树的大小的下一个原始就是右子树的根;

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        unordered_map<int,int> mp;
        TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
            int n = preorder.size();
            for(int i=0;i<n;i++) mp[inorder[i]] = i; //哈希表预统计中序各元素所在下标
            return dfs(preorder,inorder,0,n-1,0,n-1);
        }
        TreeNode* dfs(vector<int>& preorder,vector<int>& inorder,int pl,int pr,int il,int ir){
            if(pl > pr) return NULL;
            int value = preorder[pl];
            int pos = mp[value]; //找到根在中序序列中的位置
            int len = pos-il; //左子树元素个数
            auto root = new TreeNode(value); //建立根
            root->left = dfs(preorder,inorder,pl+1,pl+len,il,pos-1); //建左子树
            root->right = dfs(preorder,inorder,pl+len+1,pr,pos+1,ir); //建右子树
            return root;
        }
    };
    

    102. 二叉树的层序遍历

    以层为单位

    bfs分别统计每一层

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int>> levelOrder(TreeNode* root) {
            vector<vector<int>> result;
            if(!root) return result; //边界判断 特判root为空
            queue<TreeNode*> q;
            q.push(root);
            while(q.size()){
                vector<int> levelList;
                int len = q.size(); //循环刚进来 代表上一层的元素个数
                for(int i=1;i<=len;i++){ 
                	//把当前层每一个元素分别出队 并把左右结点入队
                    auto top = q.front();
                    q.pop();
                    levelList.push_back(top->val);
                    if(top->left) q.push(top->left);
                    if(top->right) q.push(top->right);
                }
                result.push_back(levelList);
            }
            return result;
        }
    };
    

    236. 二叉树的最近公共祖先

    思路:来源leetcode题解

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            //递归出口
            if(root == NULL || root == p || root == q) return root;
    
            //递归统计左右结点
            auto left = lowestCommonAncestor(root->left,p,q);
            auto right = lowestCommonAncestor(root->right,p,q);
    
            //只在一个子树上
            if(left == NULL) return right;
            if(right == NULL) return left;
    
            //否则left和right都非空
            //说明一个结点在其左子树 另一个结点在右子树那么当前结点就是最近公共祖先
            return root; 
        }
    };
    

    543. 二叉树的直径

    直径:树中最长的路径(从一点到另一点)

    注意:因为一开始不确定最高点是哪个,根节点不一定是最高点,比如下图样例

    所以在dfs的过程上枚举最高点,就是计算当前结点下ans的最大值

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int ans = 0; //最优值
        int diameterOfBinaryTree(TreeNode* root) {
            dfs(root);
            return ans;
        }
        int dfs(TreeNode* root){
            if(!root) return 0;
            int left = dfs(root->left);
            int right = dfs(root->right);
            //加入当前结点后的最优值: 左子树深度 + 右子树深度
            ans = max(ans,left+right); //更新当前节点下 最长直径长度
            return max(left,right); //返回当前树上 左右子树的最大值
        }
    };
    

    其它做法:
    先找到一个深度最深的端点(最高点),再把最高点作为根dfs找到新的最深距离
    https://www.cnblogs.com/fisherss/p/10914820.html

    124. 二叉树中的最大路径和

    从树中任意节点出发,达到任意节点的序列的最大路径和

    和LeetCode543思路一样,dfs的过程中枚举最优点(最高点),即最优点下路径和最大,其对应所在的一条路径上权值和最大,所在的路径为左子树路径+本身+右子树

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int ans = INT_MIN;
        int maxPathSum(TreeNode* root) {
            dfs(root);
            return ans;
        }
    
        //从当前结点root向下走的最大值
        int dfs(TreeNode* root){
            if(!root) return 0;
            int left = dfs(root->left);
            int right = dfs(root->right);
            //dfs枚举到最优点下 更新加入当前结点后的最优值  
            
            ans = max(ans,left+root->val+right); //左边最大值 + 自己 + 右边最大值
    
            /*
            //下面三行都可以省略替代为上一行 
            //因为dfs左右子树后 左右子树已达最优 只要再加入当前结点的值就行
            ans = max(ans,root->val);
            ans = max(ans,left+root->val);
            ans = max(ans,right+root->val);
            */
            //三种情况和0比较
            return max(0,max(root->val,max(left+root->val,right+root->val)));
        }
    };
    

    173. 二叉搜索树迭代器

    题目描述:

    实现一个二叉搜索树迭代器。你将使用二叉搜索树的根节点初始化迭代器。

    调用 next() 将返回二叉搜索树中的下一个最小的数。

    题目要求:

    思路:

    二叉搜索树每次返回一个最小的数,就相当于对二叉搜索树进行中序遍历

    因为二叉搜索树的左子树都比根小,右子树都比根大;即左、中、右的值依次增大

    递归方式(不满足空间要求):

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class BSTIterator {
    public:
        vector<int> v;
        int pos = 0;
        BSTIterator(TreeNode* root) {
            dfs(root);
        }
    
        void dfs(TreeNode* root){
            if(!root) return;
            dfs(root->left);
            v.push_back(root->val);
            dfs(root->right);
        }
        
        /** @return the next smallest number */
        int next() {
            return v[pos++];
        }
        
        /** @return whether we have a next smallest number */
        bool hasNext() {
            if(pos < v.size()) return true;
            return false;
        }
    };
    
    /**
     * Your BSTIterator object will be instantiated and called as such:
     * BSTIterator* obj = new BSTIterator(root);
     * int param_1 = obj->next();
     * bool param_2 = obj->hasNext();
     */
    

    迭代方式(用栈来模拟中序遍历):

    参考LeetCode94,只不过是把迭代拆开写了

    满足next函数内存是O(h),即栈中最多加入了一列深度下的节点

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class BSTIterator {
    public:
        stack<TreeNode*> stk;
        BSTIterator(TreeNode* root) {
            while(root){ //初始加入左子树入栈
                stk.push(root);
                root = root->left;
            }
        }
        
        /** @return the next smallest number */
        int next() { //O(h)
            auto p = stk.top(); //二叉搜索树中序的栈顶一定是最小的
            stk.pop();
            int result = p->val;
            p = p->right; //左子树遍历完了 根也遍历完了 就移向右子树
            while(p){
                stk.push(p);
                p = p->left;
            }
            return result;
        }
        
        /** @return whether we have a next smallest number */
        bool hasNext() {
            return !stk.empty();
        }
    };
    
    /**
     * Your BSTIterator object will be instantiated and called as such:
     * BSTIterator* obj = new BSTIterator(root);
     * int param_1 = obj->next();
     * bool param_2 = obj->hasNext();
     */
    

    297. 二叉树的序列化与反序列化

    序列化相当于先序遍历序列,NULL值用#代替;

    反序列化相当于用带#表示空值的先序序列来建树(本来只用先序序列无法建树,但是这里使用了#来代表叶节点孩子的值为空,就可以用先序建树了)

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Codec {
    public:
    
        // Encodes a tree to a single string.
        string serialize(TreeNode* root) {
            string data;
            dfs1(root,data);
            return data;
        }
    
        void dfs1(TreeNode* root,string &data){
            if(!root){
                data += "#,";
                return;
            }
            data += to_string(root->val) + ','; //先序遍历
            dfs1(root->left,data);
            dfs1(root->right,data);
        }
    
        // Decodes your encoded data to tree.
        TreeNode* deserialize(string data) {
            int index = 0;
            return dfs2(data,index);
        }
    
        TreeNode* dfs2(string &data,int &index){
            if(data[index] == '#'){ //遇到#号 要消耗一个,和一个#
                index+=2; 
                return NULL;
            }
            bool is_minus = false;
            if(data[index] == '-') { //判断是否是负数
                is_minus = true;
                index++;
            }
            int value = 0;
            while(data[index] != ','){ //求这个数的值 到下一个逗号结束
                value = value * 10 + (data[index] - '0');
                index++;
            }
            index++;
            if(is_minus) value = -value; //负数
            auto root = new TreeNode(value); //建立根节点
            root->left = dfs2(data,index); //递归求左右子树
            root->right = dfs2(data,index);
            return root;
        }
    };
    
    // Your Codec object will be instantiated and called as such:
    // Codec codec;
    // codec.deserialize(codec.serialize(root));
    
  • 相关阅读:
    万亿养老市场如何抢占商机?云巢智慧康养物联网加速器,三招化解ISV痛点!
    13个VSCode使用技巧,开启高效的开发模式
    添零占位 —— 快速生成N个0的六种办法
    使用 dumi 打包 React 组件库并生成文档站点
    Transformer架构记录(四)
    Transformer架构记录(三)
    Transformer架构记录(二)
    Transformer架构记录(一)
    NLP预训练发展小结二(Bert之后)
    p3c 插件,是怎么检查出你那屎山的代码?
  • 原文地址:https://www.cnblogs.com/fisherss/p/12960736.html
Copyright © 2011-2022 走看看