zoukankan      html  css  js  c++  java
  • LeetCode——树

    递归

    104. 二叉树的最大深度

    题目描述:给定一个二叉树,找出其最大深度。

    int maxDepth(struct TreeNode* root){
        if(root==NULL) return 0;
        int maxLeft=maxDepth(root->left)+1;
        int maxRight=maxDepth(root->right)+1;
        return maxLeft>maxRight?maxLeft:maxRight;
    }
    

    110. 平衡二叉树

    题目描述:给定一个二叉树,判断它是否是高度平衡的二叉树。

    bool isBalanced(struct TreeNode* root){
        return maxDepth(root)!=-1;
    }
    
    int maxDepth(struct TreeNode *root){
        if(root==NULL) return 0;
        int maxLeft=maxDepth(root->left);
        if(maxLeft==-1) return -1;
        int maxRight=maxDepth(root->right);
        if(maxRight==-1) return -1;
        int x=abs(maxRight-maxLeft);
        if(x>1) return -1;
        return (maxLeft>maxRight?maxLeft:maxRight)+1;
    }
    

    543. 二叉树的直径

    题目描述:给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

    分析:直径为左子树最大高度+右子树最大高度,在递归过程中实时更新最大的直径即可

    int diameterOfBinaryTree(struct TreeNode* root){
        int maxLen=0;
        maxDepth(root,&maxLen);
        return maxLen;
    }
    
    int maxDepth(struct TreeNode* root,int *maxLen){
        if(root==NULL) return 0;
        int maxLeft=maxDepth(root->left,maxLen);
        int maxRight=maxDepth(root->right,maxLen);
        int tmpLen=maxLeft+maxRight;
        if(tmpLen>*maxLen) *maxLen=tmpLen;
        return (maxLeft>maxRight?maxLeft:maxRight)+1;
    }
    

    226. 翻转二叉树

    题目描述:翻转一棵二叉树。

    分析:后序遍历求解

    struct TreeNode* invertTree(struct TreeNode* root){
        if(root==NULL) return NULL;
        struct TreeNode *l=invertTree(root->left);
        struct TreeNode *r=invertTree(root->right);
        root->left=r;
        root->right=l;
        return root;
    }
    

    617. 合并二叉树

    题目描述:给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠

    你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

    分析:

    利用前序遍历,用两个指针分别指向两棵树对应位置

    递归终止条件:指针到达某一棵树的叶子结点,于是返回另一个结点指针

    返回给上一层的信息:返回一棵处理好的根节点

    本轮的任务:从宏观来看,本轮要连接下一层返回的两个根节点,组成一棵树,并将当前位置的结点数值相加

    struct TreeNode* mergeTrees(struct TreeNode* t1, struct TreeNode* t2){
        if(t1==NULL) return t2;
        if(t2==NULL) return t1;
        t1->val+=t2->val;
        t1->left=mergeTrees(t1->left,t2->left);
        t1->right=mergeTrees(t1->right,t2->right);
        return t1;
    }
    

    112. 路径总和

    题目描述:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

    bool hasPathSum(struct TreeNode* root, int sum){
        if(root==NULL){
            return false;
        }
        if(root->left==NULL&&root->right==NULL&&root->val==sum){//叶子结点,且其值为sum
            return true;
        }
        return hasPathSum(root->left,sum-root->val)||hasPathSum(root->right,sum-root->val);//左右结点都没有路径才返回false
    }
    

    437. 路径总和 III

    题目描述:给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

    分析:

    从宏观上看,对于树中的一个结点,总的路径数包含两部分:

    1. 经过该结点的路径数
    2. 不经过该该结点,即在其子树上的路径
    int pathSumWithRoot(struct TreeNode* root,int sum){
        if(root==NULL) return 0;
        int ret=0;
        if(sum==root->val) ret++;
        ret+=pathSumWithRoot(root->left,sum-root->val)+pathSumWithRoot(root->right,sum-root->val);
        return ret;
    }
    int pathSum(struct TreeNode* root, int sum){
        if(root==NULL) return 0;
        return pathSum(root->left,sum)+pathSum(root->right,sum)+pathSumWithRoot(root,sum);
    }
    

    572. 另一个树的子树

    题目描述:给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。

    分析:

    双递归求解,外层递归用于遍历s树的每个结点,内层递归用于判断以当前结点为根节点的子树是否与t树相同

    内层递归终止条件:两个指针都为NULL,说明这条路径上对应结点值是相同的,返回true,其余情况都为false

    bool isSameTree(struct TreeNode *s,struct TreeNode *t){
        if(s==NULL&&t==NULL) return true;
        if(s==NULL||t==NULL) return false;
        if(s->val!=t->val) return false;
        return isSameTree(s->left,t->left)&&isSameTree(s->right,t->right);
    }
    bool isSubtree(struct TreeNode* s, struct TreeNode* t){
        if(s==NULL) return false;
        return isSameTree(s,t)||isSubtree(s->left,t)||isSubtree(s->right,t);
    }
    

    101. 对称二叉树

    题目描述:给定一个二叉树,检查它是否是镜像对称的。

    分析:

    首先,如果给定是空树,则必然对称

    其次分析,如果有子树,则左子树的左结点等于右子树的右结点,左子树右结点等于右子树左结点

    bool child(struct TreeNode* l,struct TreeNode* r){
        if(l==NULL&&r==NULL) return true;
        if(l==NULL||r==NULL) return false;
        if(l->val!=r->val) return false;
        return child(l->left,r->right)&&child(l->right,r->left);
    }
    bool isSymmetric(struct TreeNode* root){
        if(root==NULL) return true;
        return child(root->left,root->right);
    }
    

    111. 二叉树的最小深度

    题目描述:给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

    分析:

    递归终止条件是root为NULL,此时树高为0。当左右子树都存在时,最小深度为左右子树树高最小值+1,如果其中一棵子树为空,则最小深度就要以令一棵子树的最小深度为准

    int min(int a,int b){
        return a<b?a:b;
    }
    int minDepth(struct TreeNode* root){
        if(root==NULL) return 0;
        if(root->left==NULL) return minDepth(root->right)+1;
        if(root->right==NULL) return minDepth(root->left)+1;
        return min(minDepth(root->left),minDepth(root->right))+1;
    }
    

    404. 左叶子之和

    题目描述:计算给定二叉树的所有左叶子之和。

    int sumOfLeftLeaves(struct TreeNode* root){
        if(root==NULL) return 0;
        int res=0;
        if(root->left!=NULL&&root->left->left==NULL&&root->left->right==NULL){
            res=root->left->val;
        }
        return res+sumOfLeftLeaves(root->left)+sumOfLeftLeaves(root->right);
    }
    

    687. 最长同值路径

    题目描述:给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。

    int counter(struct TreeNode* root,int* res){
        if(root==NULL) return 0;
        int l=counter(root->left,res);
        int r=counter(root->right,res);
        int l1=0,r1=0;
        if(root->left!=NULL&&root->val==root->left->val) l1=l+1;
        if(root->right!=NULL&&root->val==root->right->val) r1=r+1;
        *res=(*res>(l1+r1)?*res:(l1+r1));
        return l1>r1?l1:r1;
    }
    int longestUnivaluePath(struct TreeNode* root){
        int res=0;
        counter(root,&res);
        return res;
    }
    

    337. 打家劫舍 III

    输入: [3,2,3,null,3,null,1]
         3
        / 
       2   3
            
         3   1
    输出: 7 
    解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.
    

    分析:

    对于当前结点来说,如果偷了这个结点,则不能偷它的左右结点,如果不偷,则可以偷左右结点

    int rob(struct TreeNode* root){
        if(root==NULL) return 0;
        int val1=root->val; 
        if(root->left!=NULL) val1+=rob(root->left->left)+rob(root->left->right);
        if(root->right!=NULL) val1+=rob(root->right->left)+rob(root->right->right);
        int val2=rob(root->left)+rob(root->right);
        return val1>val2?val1:val2;
    }
    

    后序遍历,从叶子递推到根

    void postOrder(struct TreeNode* root){
        if(root->left!=NULL) postOrder(root->left);
        if(root->right!=NULL) postOrder(root->right);
        int res1=0,res2=root->val;
        if(root->left!=NULL){
            res1+=root->left->val;
            if(root->left->left!=NULL) res2+=root->left->left->val;
            if(root->left->right!=NULL) res2+=root->left->right->val;
        }
        if(root->right!=NULL){
            res1+=root->right->val;
            if(root->right->left!=NULL) res2+=root->right->left->val;
            if(root->right->right!=NULL) res2+=root->right->right->val;
        }
        root->val=res1>res2?res1:res2;
    }
    int rob(struct TreeNode* root){
        if(root==NULL) return 0;
        postOrder(root);
        return root->val;
    }
    

    671. 二叉树中第二小的节点

    给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 20。如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值。

    输入: 
        2
       / 
      2   5
         / 
        5   7
    
    输出: 5
    说明: 最小的值是 2 ,第二小的值是 5 。
    

    分析:可以转化为找左右子树中的最小值,如果左右子树最小值都大于根结点的值,则返回两者中较小的值,其他情况返回最大值

    int myFind(struct TreeNode* root,int val){
        if(root==NULL) return -1;
        if(root->val>val) return root->val;
        int l=myFind(root->left,val);
        int r=myFind(root->right,val);
        if(l>val&&r>val) return l<r?l:r;
        return l>r?l:r;
    }
    int findSecondMinimumValue(struct TreeNode* root){
        return myFind(root,root->val);
    }
    

    层次遍历

    637. 二叉树的层平均值

    给定一个非空二叉树, 返回一个由每层节点平均值组成的数组

    class Solution {
        public List<Double> averageOfLevels(TreeNode root) {
            List<Double> lst = new ArrayList<>();
            if(root==null) return lst;
            Queue<TreeNode> q=new LinkedList<>();
            q.add(root);
            while(!q.isEmpty()){
                double sum=0;
                int cnt=q.size();
                for(int i=0;i<cnt;i++){
                    TreeNode tmp=q.poll();
                    sum+=tmp.val;
                    if(tmp.left!=null) q.add(tmp.left);
                    if(tmp.right!=null) q.add(tmp.right);
                }
                lst.add(sum/cnt);
            }
            return lst;
        }
    }
    

    513. 找树左下角的值

    给定一个二叉树,在树的最后一行找到最左边的值。

    BFS:
    使用层序遍历,遍历顺序为自右向左,最后一个结点即为所求

    class Solution {
        public int findBottomLeftValue(TreeNode root) {
            Queue<TreeNode> q = new LinkedList<>();
            q.add(root);
            while(!q.isEmpty()){
                root=q.poll();
                if(root.right!=null) q.add(root.right);
                if(root.left!=null) q.add(root.left);
            }
            return root.val;
        }
    }
    

    DFS:

    void dfs(struct TreeNode* root,int depth,int* maxDepth,int* ret){
        if(root==NULL) return;
        if(root->left==NULL&&root->right==NULL){
            if(depth>=*maxDepth){
                *maxDepth=depth;
                *ret=root->val;
            }
            return;
        }
        dfs(root->right,depth+1,maxDepth,ret);
        dfs(root->left,depth+1,maxDepth,ret);
    }
    int findBottomLeftValue(struct TreeNode* root){
        int maxDepth=-1,ret;
        dfs(root,0,&maxDepth,&ret);
        return ret;
    }
    

    前中后序遍历

    144. 二叉树的前序遍历

    非递归步骤

    1. 开始根结点入栈
    2. 然后开始循环:栈顶结点出栈,依次将右结点和左结点入栈,直至栈空
    class Solution {
        public List<Integer> preorderTraversal(TreeNode root) {
            Stack<TreeNode> st=new Stack<>();
            List<Integer> lst=new ArrayList<>();
            if(root==null) return lst;
            st.push(root);
            while(!st.isEmpty()){
                TreeNode tmp=st.pop();
                lst.add(tmp.val);
                if(tmp.right!=null) st.push(tmp.right);//先右后左,保证先序遍历
                if(tmp.left!=null) st.push(tmp.left);
            }
            return lst;
        }
    }
    

    94. 二叉树的中序遍历

    给定一个二叉树,返回它的中序 遍历。

    颜色标记法(作为模板背诵)

    1. 使用颜色标记结点,未访问的结点为白色(用0表示),访问过的为灰色(用1表示)
    2. 如果遇到结点为白色,则将其标记为灰色,然后将右结点、自身、左结点依次入栈
    3. 如果遇到结点为灰色,则输出
    class Solution {
        class ColorNode{
            TreeNode node;
            int color;
            public ColorNode(TreeNode node,int color){
                this.node=node;
                this.color=color;
            }
        }
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> lst=new ArrayList<>();
            Stack<ColorNode> st=new Stack<>();
            if(root==null) return lst;
            st.push(new ColorNode(root,0));
            while(!st.isEmpty()){
                ColorNode tmp=st.pop();
                TreeNode treeTmp=tmp.node;
                if(tmp.color==0){
                    if(treeTmp.right!=null) st.push(new ColorNode(treeTmp.right,0));
                    st.push(new ColorNode(treeTmp,1));
                    if(treeTmp.left!=null) st.push(new ColorNode(treeTmp.left,0));
                }else{
                    lst.add(treeTmp.val);
                }
            }
            return lst;
        }
    }
    

    145. 二叉树的后序遍历

    给定一个二叉树,返回它的 后序 遍历。

    class Solution {
        class ColorNode{
            int color;
            TreeNode node;
            public ColorNode(TreeNode node,int color){
                this.node=node;
                this.color=color;
            }
        }
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> lst=new ArrayList<>();
            Stack<ColorNode> st=new Stack<>();
            if(root==null) return lst;
            st.push(new ColorNode(root,0));
            while(!st.isEmpty()){
                ColorNode tmp=st.pop();
                if(tmp.color==0){
                    st.push(new ColorNode(tmp.node,1));
                    if(tmp.node.right!=null) st.push(new ColorNode(tmp.node.right,0));
                    if(tmp.node.left!=null) st.push(new ColorNode(tmp.node.left,0));
                }else{
                    lst.add(tmp.node.val);
                }
            }
            return lst;
        }
    }
    

    BST

    669. 修剪二叉搜索树

    给定一个二叉搜索树,同时给定最小边界L 和最大边界R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

    struct TreeNode* trimBST(struct TreeNode* root, int L, int R){
        if(root==NULL) return NULL;
        if(root->val>R) return trimBST(root->left,L,R);
        if(root->val<L) return trimBST(root->right,L,R);
        root->left=trimBST(root->left,L,R);
        root->right=trimBST(root->right,L,R);
        return root;
    }
    

    230. 二叉搜索树中第K小的元素

    给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

    算法1:中序遍历

    BST的中序序列即为元素的升序

    void inOrder(struct TreeNode* root,int k,int* cnt,int* ret){
        if(root==NULL) return;
        inOrder(root->left,k,cnt,ret);
        (*cnt)++;
        if(*cnt==k){
            *ret=root->val;
            return;
        }
        inOrder(root->right,k,cnt,ret);
    }
    int kthSmallest(struct TreeNode* root, int k){
        int cnt=0,ret=0;
        inOrder(root,k,&cnt,&ret);
        return ret;
    }
    

    算法2:递归

    统计左子树的结点数,如果恰好为k-1,则该结点即为所求,>k-1时,说明结点在左子树上,<k-1时,说明结点在右子树上

    int count(struct TreeNode* root){
        if(root==NULL) return 0;
        return count(root->left)+count(root->right)+1;
    }
    int kthSmallest(struct TreeNode* root, int k){
        int cnt=count(root->left);
        if(cnt==k-1) return root->val;
        if(cnt>k-1) return kthSmallest(root->left,k);
        return kthSmallest(root->right,k-cnt-1);
    }
    

    538. 把二叉搜索树转换为累加树

    给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。

    输入: 原始二叉搜索树:
                  5
                /   
               2     13
    
    输出: 转换为累加树:
                 18
                /   
              20     13
    

    分析:要想找出所有大于本结点的值,应该采用"右中左"的顺序遍历,这样得到的序列为降序

    void traver(struct TreeNode* root,int* sum){
        if(root==NULL) return;
        traver(root->right,sum);
        *sum+=root->val;
        root->val=*sum;
        traver(root->left,sum);
    }
    struct TreeNode* convertBST(struct TreeNode* root){
        int sum=0;
        traver(root,&sum);
        return root;
    }
    

    235. 二叉搜索树的最近公共祖先

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

    struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
        if(root->val<p->val&&root->val<q->val) return lowestCommonAncestor(root->right,p,q);
        if(root->val>p->val&&root->val>q->val) return lowestCommonAncestor(root->left,p,q);
        return root;
    }
    

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

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

    struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
        if(root==NULL) return NULL;
        if(root==p||root==q) return root;
        struct TreeNode* l=lowestCommonAncestor(root->left,p,q);
        struct TreeNode* r=lowestCommonAncestor(root->right,p,q);
        if(l!=NULL&&r!=NULL) return root;
        if(l==NULL&&r==NULL) return NULL;
        return l==NULL?r:l;
    }
    
  • 相关阅读:
    Project Euler Problem 11: Largest product in a grid
    Project Euler Problem 10: Summation of primes
    Project Euler Problem 10: Summation of primes
    Project Euler Problem 9: Special Pythagorean triplet
    Project Euler Problem 9: Special Pythagorean triplet
    Project Euler Problem 8: Largest product in a series
    Project Euler Problem 8: Largest product in a series
    Project Euler Problem 7: 10001st prime
    Project Euler Problem 7: 10001st prime
    Project Euler Problem 48: Self powers
  • 原文地址:https://www.cnblogs.com/xkf97/p/12714911.html
Copyright © 2011-2022 走看看