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));
    
  • 相关阅读:
    mysq 日期相减
    说说时间观与时间管理——北漂18年(71)
    ionic之切换开关
    ionic之单选框
    SELECT ... LOCK IN SHARE MODE和SELECT ... FOR UPDATE locks在RR模式下可以看到最新的记录
    14.5.2.3 Consistent Nonlocking Reads 一致性非锁定读
    14.5.2.2 autocommit, Commit, and Rollback
    14.5.2 事务隔离级别
    对于唯一索引使用唯一条件搜索, InnoDB 只锁定找到的index record,不是它之前的区间
    mysql explain 解释
  • 原文地址:https://www.cnblogs.com/fisherss/p/12960736.html
Copyright © 2011-2022 走看看