zoukankan      html  css  js  c++  java
  • LeetCode树专题(递归)(未完成)

    递归

    一棵树要么是空树,要么有两个指针,每个指针指向一棵树。树是一种递归结构,很多树的问题可以使用递归来处理。

    1. 树的高度

    104. Maximum Depth of Binary Tree (Easy)

    Leetcode / 力扣

    传入的TteeNode root 结点有左结点left右结点right两个属性,是跟root一样的TreeNode。所以是递归结构。二叉链表的存储结构。

    该题的递归过程分析在第3题。现在是懂了,看到再分析一下看是不是真的记住了。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public int maxDepth(TreeNode root) {
            if(root==null){
                return 0;
            }
            return Math.max(maxDepth(root.left),maxDepth(root.right))+1;//返回求深度,DFS。找左儿子和右儿子的深度最大的那个加1
            
        }
    }

    2. 平衡树

    110. Balanced Binary Tree (Easy)

    Leetcode / 力扣

        3
       / 
      9  20
        /  
       15   7

    平衡树左右子树高度差都小于等于 1

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        boolean result = true;//定义一个为ture的全局变量 可是很难想到1002
        public boolean isBalanced(TreeNode root) {
            
            maxDepth(root);
            return result;
        }
        
        public int maxDepth(TreeNode root){
            if(root==null) return 0;
            if((Math.abs(maxDepth(root.left) - maxDepth(root.right))) > 1){//没有这一步的话 前面就直接返回事先定好的true。
    意思是树上任意节点左右子树深度若差值大于1了的话,把全局变量在这里改成了一个false.但不影响求树的最大深度!! result
    = false; } return Math.max(maxDepth(root.left),maxDepth(root.right))+1;//返回的依然是树的最大深度。但重要的是if条件判断 } }

    主判断方法为isBalanced(),其中调用了maxDepth()

    maxDepth()方法中,我们通过递归,计算了每个节点的左右子树的深度并进行比较,若差距大于1,则将result置为false(不平衡)

    这一题比上一题这个判断

    3. 两节点的最长直径

    543. Diameter of Binary Tree (Easy)

    Leetcode / 力扣

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

    Input:
    
             1
            / 
           2  3
          / 
         4   5
    
    Return 3, which is the length of the path [4,2,1,3] or [5,2,1,3].

    都没有思路,希望第二次做时可以有思路

    答案解析:

    又是换一种方式用递归计算深度,然后这次需要两边最大的深度加起来就是最长路径

    递归出口很重要

    这一题总结下两题的求深度(深度优先搜索):

     

     这个第一题的递归过程是1的左儿子2先进入这一行里的递归方法,执行方法回到第一行,看2是否为空,不为空往下走,找到左儿子4继续这个方法,又从第一行从上往下,先看4是否为空,不为空往下走,找4的左儿子执行方法,为空了此时,retrun 0出了这一行递归,L=0。继续往下一行代码走。

    又进入递归方法,此时rt还是4,找4的右儿子(后1/2)从递归方法第一行执行,为空了此时,retrun 0出了这一行递归,R=0。

    4的前1/2和后1/2都完成了。。。。

    然后往下走 return max(0,0)+1  =1 返回的是4的深度

    然后得返回上一层到2的右儿子(后1/2...)   好突然

    找到右儿子5,又进入递归方法第一行,由于是空 return 0 。找5的右儿子,又进入递归方法第一行,由于是空return 0...

    5的完成,往下走return 1返回的是5的深度

    2也前后都完成了,往下走return max(1,1)+1 =2 返回的是2的深度  好突然

    就是每一个结点得左右儿子完成,return出一个数,才返回上一层

    返回到1的右儿子3执行递归方法,左儿子空=0,右儿子空=0,return max(0,0)+1 =1是3的深度

    然后1的深度就是max(2,1)+1=3

    总结过程就是遇到递归方法参数进去,返回到递归方法第一行,一直执行到递归出口,此时的最底层执行下一个语句,若又是递归则又到第一行往下执行,若遇到递归出口,则可以该层完成后1/2,返回上一层完成递归后半段1/2整体完成直到递归出口。(走一遍就明白了)。关于什么时候用,应该是遇到传入的数据结构是一种递归结构去实现某个方法时,(链表好像也可以? 或者像阶乘这种方法

    然后我们通过左右遍历返回有可能就认识这个3就是答案,这在上图是对的,但是在下图就不对了。

    如果是下图,按上面从1出发的思路找到3条,就不对了。最多应该是不经过1的4条。

     注意可能并不穿过根节点,这里主方法中的Max=depth(root.left)+depth(root.right)是只取经过主节点的左加右长度!!!

    改掉这个代码,不用Max只等于root的左加右,改成Max--任意节点的左加右存住最大的那个返回Max给主方法。

    这个改的过程有点难理解,但是结合刚刚递归的过程,加上如上图这种情况分析递归,当从5后1/2的完成返回到2这里的时候,2的后1/2完成,此时L是4返回的2,R是5返回的2,L+R=4,Max存住了。就算再返回到1,1的后1/2返回的R=0,L为2返回的3,L+R =3 其实小于2的左右相为4.

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        int max=0;
        public int diameterOfBinaryTree(TreeNode root) {
            deepth(root);
            return max;
        }
    public int deepth(TreeNode root){ if(root==null){ return 0; } int L,R; L=deepth(root.left);//左子的深度 R=deepth(root.right);//右子的深度 max=Math.max(L+R,max);//某个节点为头结点时,此时更新的最大的左子加右子的深度,是最长的路径 return Math.max(L,R)+1;//这是节点的深度的计算。但是我们重要的是return的max。上一题也是 } }

    4. 翻转树

    226. Invert Binary Tree (Easy)

    Leetcode / 力扣

    思路:

        public TreeNode invertTree(TreeNode root) {
            if(root==null){
                return null;
            }
            invertTree(root.left);
            invertTree(root.right);
            root.left=root.right;//错了。。。。。
            return root;
        }

    思路是对的,交换语句写错了!!这是赋值。。不是交换。。。

    class Solution {
        public TreeNode invertTree(TreeNode root) {
            if(root==null){
                return null;
            }
            invertTree(root.left);
            invertTree(root.right);
    
            TreeNode temp;
            temp=root.right;
            root.right=root.left;
            root.left=temp;
            
            return root;
        }
    }

    5. 归并两棵树

    617. Merge Two Binary Trees (Easy)

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

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

    Leetcode / 力扣

    Input:
           Tree 1                     Tree 2
              1                         2
             /                        / 
            3   2                     1   3
           /                              
          5                             4   7
    
    Output:
             3
            / 
           4   5
          /    
         5   4   7

    思路是列出三种情况,然后递归相加。怎么写val想加呢?

    错误之处:

    1.应该是先相加,再递归。(前序遍历就是这样,先打印值,再判断有没有左,有左就进入递归,再判断有没有右,有右再进入递归。)

    2.相加的结果直接用构造方法new出结果结点传入值作为参数即可。

    3.左右递归的结果分别要做为结果结点的左子树和右子树。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }//构造方法new一个就是
     * }
     */
    class Solution {
        public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
            if(t1==null && t2==null) return null;
            if(t1==null) return t2;
            if(t2==null) return t1;
    
            TreeNode root = new TreeNode(t1.val+t2.val);
            root.left= mergeTrees(t1.left,t2.left);
            root.right=mergeTrees(t1.right,t2.right);
            return root;
    
        }
    }

    6. 判断路径和是否等于一个数

    Leetcdoe : 112. Path Sum (Easy)

    Leetcode / 力扣

    Given the below binary tree and sum = 22,
    
                  5
                 / 
                4   8
               /   / 
              11  13  4
             /        
            7    2      1
    
    return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

    路径和定义为从 root 到 leaf 的所有节点的和。

    emmm没有想法。。

    答案:

    最直接的方法就是利用递归,遍历整棵树:如果当前节点不是叶子,对它的所有孩子节点,递归调用 hasPathSum 函数,其中 sum 值减去当前节点的权值如果当前节点是叶子,检查 sum 值是否为 0,也就是是否找到了给定的目标和。

    (和是摊到每个节点的,所以一路减下来到叶子结点的值就是叶子结点的值)

    class Solution {
      public boolean hasPathSum(TreeNode root, int sum) {
        if (root == null)
          return false;
    
        sum -= root.val;
        if ((root.left == null) && (root.right == null))//一般是判断节点为空 但这里需要判断是否是叶子 没到下一步
          return (sum == 0);//到达了叶子,判断是否达到了目标值。=0则说明加上这个叶子值达到了目标
    return hasPathSum(root.left, sum) || hasPathSum(root.right, sum);//可以分开看 只要左右有一个达到为==0为ture就行 } }

    这题有点难想到。但愿下次会做了。。emmmm1003还是不会

    7. 统计路径和等于一个数的路径数量

    437. Path Sum III (Easy)

    Leetcode / 力扣

    root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
    
          10
         /  
        5   -3
       /     
      3   2   11
     /    
    3  -2   1
    
    Return 3. The paths that sum to 8 are:
    
    1.  5 -> 3
    2.  5 -> 2 -> 1
    3. -3 -> 11

    路径不一定以 root 开头,也不一定以 leaf 结尾,但是必须连续。

    思路是第三题也不是必须经过root,在中间加一个存住满足的树。(应该是想到让其他节点为头结点时

    class Solution {
        public int pathSum(TreeNode root, int sum) {
            if(root == null){
                return 0;
            }
            int count=0;
            sum-=root.val;
            int left = pathSum(root.left,sum);
            int right = pathSum(root.right,sum-left);//错的!!
            if(left+right == sum){
                count++;
            }
            return count;
    
        }
    }

    错了。。int right明显就不对。

    答案:

    题目要求 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点) 。这就要求我们只需要去求三部分即可:

    以当前节点作为头结点的等于sum路径数量
    以当前节点的左孩子作为头结点的等于sum路径数量
    以当前节点的右孩子作为头结点的等于sum路径数量
    将这三部分之和作为最后结果即可。1003:其实也是递归

    最后的问题是:我们应该如何去求以当前节点作为头结点的路径的数量?这里依旧是按照树的遍历方式模板,每到一个节点让sum-root.val,并判断sum是否为0,如果为零的话,则找到满足条件的一条路径。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public int pathSum(TreeNode root, int sum) {
            if(root == null) return 0;
            //当前节点开始的所有满足条件的路径总数
            int result = countPath(root,sum);
            //当前节点左子节点开始的满足条件路径总数
            int a = pathSum(root.left,sum);
            //当前节点右子节点开始的满足条件路径总数
            int b = pathSum(root.right,sum);
            return result+a+b;
        }
        public int countPath(TreeNode root,int sum){//这个方法是传入作为头结点时,计算等于sum的路径数
            if(root == null)  return 0;
            sum = sum - root.val;
            int result = sum == 0 ? 1:0;//result计数
            //当前节点开始的所有满足条件的路径总数分为左,右两条路径
            int left =count(root.left,sum);
            int right = count(root.right,sum);
            return result+left+right;
        }
    }

    不知道什么时候需要分开另外写方法。。第三题也另外写了方法。。

    8. 子树

    572. Subtree of Another Tree (Easy)

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

    Leetcode / 力扣

    Given tree s:
         3
        / 
       4   5
      / 
     1   2
    
    Given tree t:
       4
      / 
     1   2
    
    Return true, because t has the same structure and node values with a subtree of s.
    
    Given tree s:
    
         3
        / 
       4   5
      / 
     1   2
        /
       0
    
    Given tree t:
       4
      / 
     1   2
    
    Return false.

     思路:可以像上一题一样,

    class Solution {
        public boolean isSubtree(TreeNode s, TreeNode t) {
            if(s==null||t==null){
                return false;
            }
            return (sub(s,t)||isSubtree(s.left,t)||isSubtree(s.right,t));
        }
    
        public boolean sub(TreeNode s,TreeNode t){
            if(s==null||t==null){
                return false;
            }
            if(s==t){//错了 这是内存地址判断了。。。应该用值判断 但思路是对的 判断头或左子或右子 有一个是就是
                return true;
            }
            sub(s.left,t);
            sub(s.right,t);
            return true;
        }
    }

    错了。。。。。。。啥都return true了。。。

     最下面一行改成

            return sub(s.left,t)||sub(s.right,t);

    又错了。。。变成啥都return false了。。。

    看答案,首先第一行就错了,应该是

            if (t == null) return true;   // t 为 null 一定都是 true
            if (s == null) return false;  // 这里 t 一定不为 null, 只要 s 为 null,肯定是 false

    然后看s和t是否一样不能用s==t....要用值判断。。。。我这么这么二居然直接用== 这是存的地址。。。

    答案:

    class Solution {
        public boolean isSubtree(TreeNode s, TreeNode t) {//判断是否为子树
            if (t == null) return true;   // t 为 null 一定都是 true
            if (s == null) return false;  // 这里 t 一定不为 null, 只要 s 为 null,肯定是 false
            return isSubtree(s.left, t) || isSubtree(s.right, t) || isSameTree(s,t);//s判是否值相同,s的左右再判断是否是子树
        }
    
        /**
         * 判断两棵树是否相同
         */
        public boolean isSameTree(TreeNode s, TreeNode t){
            if (s == null && t == null) return true;//有可能一开始就是两个null是same的,也有可能递归到了最底层它们的值都是相等的 
            if (s == null || t == null) return false;//注意这里是蟠相同不是判子树了所以不能为null了
            if (s.val != t.val) return false;//头结点处的值是否相同 不相等直接false
            return isSameTree(s.left, t.left) && isSameTree(s.right, t.right);//若相同,判断左子和右子递归该方法来判断值是否相同
        }
    }
    
    作者:kelly2018
    链接:https://leetcode-cn.com/problems/subtree-of-another-tree/solution/java-di-gui-ban-by-kelly2018/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    9. 树的对称

    101. Symmetric Tree (Easy)

    给定一个二叉树,检查它是否是镜像对称的。

    例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    Leetcode / 力扣

        1
       / 
      2   2
     /  / 
    3  4 4  3

    emmm这每层情况都有变化啊,不能再用上一题和上上题的思路了。

    就得从1开始做判断吧?我的思路:把从第二层开始另起方法。。

    class Solution {
        public boolean isSymmetric(TreeNode root) {
            if(root == null){
                return true;
            }
            
            if(root.left.val==root.right.val){
                return (yes(root.left,root.rig
            }
            return false;
        }
    
        public boolean yes(TreeNode left,TreeNode right){
            if(left==null&&right==null){
                return true;
            }
            if(left == null||right==null){
                return false;
            }
    
            if(left.left.val!=right.right.val||left.right.val!=right.left.val){//错了 空指针异常了。。
                return false;
            }
            return (yes(left.left,left.right)&&yes(right.left,right.right));
    
        }
        
    }

    答案:

     广度周游用队列??没有见过。。

    也是从子树第二层开始看。然后我是在主方法中判断他们的两个根结点的值是否相同。相同才可进入下面方法。这样造成了空指针异常且多此一举了。因为其实后面用left.left和right.right再传入后也要判断值是否相等,我没看出这第二层本身就开始递归了。

    class Solution {
        public boolean isSymmetric(TreeNode root) {
            if(root == null){
                return true;
            } 
                return (yes(root.left,root.right));//改了这里直接传入
        }
    
        public boolean yes(TreeNode left,TreeNode right){
            if(left==null&&right==null){
                return true;
            }
            if(left == null||right==null){
                return false;
            }
    
            if(left.val!=right.val){//改了这里判断传入的两个的值 
                return false;
            }
            return (yes(left.left,right.right)&&yes(left.right,right.left));//改了这里 递归在第二层的子树们开始
        } 
    }

    方法2:用队列

     

    加入根节点两遍,进入while循环,取出看这俩值相等的话,再加入一个根节点的左子,一个根节点的右子,继续循环。

    10. 最小路径

    111. Minimum Depth of Binary Tree (Easy)

    Leetcode / 力扣

    树的根节点到叶子节点的最小路径长度

     这不就是第一题一模一样的思路吗

     错了。。当只有左子没有右子时,他去选择右子返回0了

     不知道咋改。。。

    答案:

    因为题1是只需要有一条最大就行,不用管子树=null的情况。这里需要考虑一下各种情况。

    又改错了。。。

     而且这样的顺序错了

    答案就得这样顺序:

    class Solution {
        public int minDepth(TreeNode root) {
            //1.若当前节点为空,直接返回0
              if(root==null) return 0;
            //2.左孩子和有孩子都为空的情况,说明到达了叶子节点,直接返回1即可
              if(root.left==null && root.right==null) return 1;
            //3.如果左孩子和由孩子其中一个为空,说明ldepth1和rdepth有一个必然为0,所以可以返回ldepth + rdepth + 1;
              int ldepth = minDepth(root.left);
              int rdepth = minDepth(root.right);
             if(root.left==null||root.right==null) return ldepth+rdepth+1;
            //4.最后一种情况,也就是左右孩子都不为空,返回最小深度+1即可
            return Math.min(ldepth,rdepth)+1;
        }
    }

    11. 统计左叶子节点的和

    404. Sum of Left Leaves (Easy)

    计算给定二叉树的所有左叶子之和。

    Leetcode / 力扣

        3
       / 
      9  20
        /  
       15   7
    
    There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24.

     emmm应该要另写方法得出叶子,看答案吧。。

    答案这个有点像第二题第三题那样的结构,直接传入root调用方法在方法里判断root(必须从root出发的好像都这样,有一个全局变量用来返回),这里多传入一个false。

    class Solution {
        int sum = 0;
    
        public int sumOfLeftLeaves(TreeNode root) {
            return getSum(root, false);
        }
    
        private int getSum(TreeNode root, boolean isLeft){//传入结点左子值会通过递归全部加到sum里面
            if(root != null){
                if(isLeft && root.left == null && root.right == null){//满足isLeaf=true,且没有左儿子没有右儿子
                    sum += root.val;//左叶子和
                }else{
                    getSum(root.left, true);//是左边才设为ture
                    getSum(root.right, false);//如果是求所有叶子节点相加,就把这里为true了
                }
            }
          return sum; } } 作者:Omooo 链接:https:
    //leetcode-cn.com/problems/sum-of-left-leaves/solution/chao-ji-rong-yi-li-jie-qi-shi-he-qiu-quan-lu-jing-/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    12. 相同节点值的最大路径长度

    687. Longest Univalue Path (Easy)

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

    Leetcode / 力扣

                 1
                / 
               4   5
              /    
             4   4   5
    
    Output : 2

    emmm有点没看懂题目,最长的路径,节点的值有相同的?和哪个相同?

    明白了,路径长度为值。就是找最长的路经。

     第3题是最大直径,这里是最大路经。

    答案和第三题还有点像,但这里要用到值。

    跟着第三题的思路只写出求树中以某个结点为根的最大值。。。

    class Solution {
        int total = 0;
        public int longestUnivaluePath(TreeNode root) {
            maxLength(root);
            return total;
        }
        public int maxLength (TreeNode root){
            if(root==null){
                return 0;
            }
            int L,R;
            
            L=maxLength(root.left);
            R=maxLength(root.right);
            total = Math.max(L+R+root.val,total);
            return (Math.max(L,R))+root.val;
        }
    }

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        private int path = 0;
    
        public int longestUnivaluePath(TreeNode root) {
              dfs(root);
              return path;
        }
    
        private int dfs(TreeNode root){//DFS深度优先搜索 返回值为路径
              if (root == null) return 0;
              int left = dfs(root.left);
              int right = dfs(root.right);
              int leftPath = root.left != null && root.left.val == root.val ? left + 1 : 0;//??
              int rightPath = root.right != null && root.right.val == root.val ? right + 1 : 0;//???
              path = Math.max(path, leftPath + rightPath);
              return Math.max(leftPath, rightPath);
        }
    }

    可能还是没理解题目。。。看不懂代码。。。

    先跳了。。。

    明白了 他是找一条值全部相同的最长路径,不一定经过当前的根节点

    class Solution {
        int ans;
        public int longestUnivaluePath(TreeNode root) {
            ans = 0;
            longestPath(root);
            return ans;
        }
        //递归函数功能:搜寻以node为起点的最长同值路径:要么是以node为起点的左子树,要么是以node为起点的右子树
        public int longestPath(TreeNode node) {
            if (node == null) return 0;
            int maxLorRres=0;
            int left = longestPath(node.left); //node左子树的最长同值路径
            int right = longestPath(node.right);//node右子树的最长同值路径
            //这种情况对于寻找最长同值路径长有帮助,对于搜索以root为路径起始点的最长路径没有帮助
            if (node.left != null && node.left.val == node.val&&node.right != null && node.right.val == node.val) {
                ans=Math.max(ans, left + right+2);
            }
            //从左右子树中选择最长的同值路径
            if(node.left!=null&&node.left.val == node.val){
                maxLorRres=left+1;
            }
            if(node.right!=null&&node.right.val==node.val){
                maxLorRres=Math.max(maxLorRres,right+1);
            }
            //从ans与maxLorRres中更新最大值
            ans=Math.max(ans,maxLorRres);
            return maxLorRres; //所以你能知道为什么返回这个值了吗?

    回答一下为什么最后返回的maxLorRres而不是ans,首先这个递归函数的返回值是Int,肯定用来计数的。
    ans其实是作者利用这个递归函数在函数中所求的值,与递归条件,返回值什么无关,那么所有的递归出口都将在int maxLorRres=0;这行代码之后,
    则 maxLorRres则是已经被申明了,后续的if判断条件则是在统计这个 maxLorRres的值,而递归的形式则是递归左子树或者右子树
    } } 作者:Chuancey 链接:https://leetcode-cn.com/problems/longest-univalue-path/solution/guan-yu-di-gui-si-lu-de-chao-xiang-xi-ge-ren-jian-/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    13. 间隔遍历

    337. House Robber III (Medium)

    Leetcode / 力扣

         3
        / 
       2   3
           
         3   1
    Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

     直接看答案:

    总体思路为:分别计算单层数据的和与双层数据的和,返回较大的那个值。其实就是简单递归的应用啊。。没反应过来递归结构。。

    单层数据之和的计算:当前节点的值,加上左子节点的两个子节点的和,再加上右子节点的两个子节点的和。

    双层数据之和的计算:当前节点的两个子节点的值之和。

    class Solution {
        public int rob(TreeNode root) {
            //若当前节点为null,直接返回0
            if(root==null) return 0;
            //计算val1(表示单层数据的和)
            int val1=root.val;//重要!!!!
            //如果当前节点的左节点不为null,那就将当前节点的值加上左节点的两个子节点的值
            if(root.left!=null) val1+=rob(root.left.left)+rob(root.left.right);
            //如果当前节点的右节点不为null,那就将当前节点的值加上右节点的两个子节点的值
            if(root.right!=null) val1+=rob(root.right.left)+rob(root.right.right);
            //计算val2(表示双层数据的和)只用看它的左右节点
            int val2=rob(root.left)+rob(root.right);
            //返回val1与val2中更大的那个值
            return Math.max(val1,val2);
        }
    }

    14. 找出二叉树中第二小的节点

    671. Second Minimum Node In a Binary Tree (Easy)

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

    给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。

    Leetcode / 力扣

    Input:
       2
      / 
     2   5
        / 
        5  7
    
    Output: 5

    一个节点要么具有 0 个或 2 个子节点,如果有子节点,那么根节点是最小的节点。

    我的思路用起了优先队列。。但是不知道怎么遍历取到有左右子的结点。。。

    答案:

    原来人家本来就是排好序的。。从小到大。。。

    思路分析:

    首先根据题目描述,根结点值一定小于或者等于子结点值,这就是一个最小堆,根结点值就是整个树中的最小值,所以要找的第二小值,就是除去根结点值的最小值,为了方便使用rootValue表示这棵树根节点的值。
    树的题一般考虑递归。考虑到题目所求,递归函数的返回值应该定义为以节点x为根的树中非rootValue的最小值。由于一直需要信息rootValue,所以递归函数的参数除了结点还有rootValue。(这就有点想isLeft的那个题了)
    对于以TreeNode x为根的结点,
    如果其值不为rootValue,那么它的值就是以它为根的树中非根结点值的最小值
    如果它的值为rootValue,而且其已经是叶子结点x.left == null,在以它为根的树中没有找到非根结点值的最小值,返回失败标志-1。
    如果它的值为rootValue,但它还有左右子树,就去找左右子树的非根结点值的最小值,分别为leftMin, rightMin
    如果leftMin == -1,左子树查找失败,返回右子树的查找结果(也可能是失败,但失败也是返回-1,也还是rightMin)。
    同理rightMin == -1,返回左子树的查找结果
    如果左右都没有查找失败,都找到了非根结点值的局部最小值,就要选择其中更小的一个返回。
    时间复杂度为O(n)O(n), 空间复杂度与树高成正比。

    class Solution {
       public int findSecondMinimumValue(TreeNode root) {
            if(root == null)
                return -1;
            return find(root, root.val);
        }
    
        /**
         * 按照题目描述,这个最上面的元素就是最小的元素。用rootValue表示最小值
         * 找到和rootValue值不相同的最小值,与rootValue不相同的最小值其实就是第二小的值。
         */
        private int find(TreeNode x, int rootValue){
            if(x.val != rootValue) // 如果当前结点不等于根结点,那么值为以x为根的最小的非rootValue的值。
                return x.val;//递归终点1
    // 这之下都是 当前结点值为根结点值的情况 if(x.left == null) // 如果它的值为rootValue,而且其已经是叶子结点x.left == null,在以它为根的树中没有找到非根结点值的最小值,返回失败标志-1。 return -1;//递归终点2
    int leftMin = find(x.left, rootValue);//左右两边分别找最小值,因为递归终点1或2出来的一定是不等于root值的第2小的val或者-1 int rightMin =
    find(x.right, rootValue);//传入的还是最小值,根结点的值!
    if(leftMin == -1) return rightMin; if(rightMin == -1) return leftMin;
    return Math.min(leftMin, rightMin);//左右两边比较各自的最小值 } } }

    作者:ustcyyw
    链接:https://leetcode-cn.com/problems/second-minimum-node-in-a-binary-tree/solution/671java-0msdi-gui-hen-jian-ji-e-by-ustcyyw/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    哎呀好难啊不会

    从230来的,想到了671所以理解了理解了。。

  • 相关阅读:
    【bzoj1707/Usaco2007 Nov】tanning分配防晒霜——贪心+优先队列
    【bzoj1754/Usaco2005 qua】Bull Math——高精度乘法
    【bzoj1709/Usaco2007 Oct】Super Paintball超级弹珠——递推
    【bzoj2060/Usaco2010 Nov】Visiting Cows 拜访奶牛——树形dp
    【bzoj1710/Usaco2007 Open】Cheappal 廉价回文——区间dp
    【bzoj1828/Usaco2010 Mar】balloc 农场分配——贪心+差分+优先队列
    【bzoj4552/Tjoi2016&Heoi2016】排序——二分+线段树/平衡树+线段树分裂与合并
    【bzoj2083/Poi2010】Intelligence test——二分+贪心
    【bzoj1596/Usaco2008 Jan】电话网络——dfs
    【bzoj1782/Usaco2010 Feb】slowdown 慢慢游——dfs序+树状数组
  • 原文地址:https://www.cnblogs.com/gezi1007/p/13028890.html
Copyright © 2011-2022 走看看