LeetCod--树

文章目录

  • 一、“树”基础(来自LeetCode)
  • 二、“树”题目--递归
    • 1.二叉树的最大深度(题号:104,Easy) 第2次
    • 2.平衡二叉树
    • 3.二叉树的直径
    • 4.路径总和
    • 5.合并二叉树
    • 6.翻转二叉树
    • 7.统计路径和等于一个数的路径数量
    • 8.另一个树的子树(题号:572)
    • 9.对称二叉树(题号:101)
    • 10.二叉树的最小深度
    • 11.左叶子之和(题号:404) 第1次
    • 12.最长节点值相同的路径(题号:687) 有待进一步理解???
    • 13.打家劫舍 III,间隔遍历(题号:337,Medium) 第二遍
    • 14.二叉树中第二小的节点(题号:671) 第一遍
    • 15.相同的树(题号:100) 第1次
    • 16.求根到叶子节点数字之和(题号:129) 第1次
    • 17.二叉树的所有路径(题号:257) 第1次
  • 三、“树”题目--遍历
    • 1.二叉树的层平均值(题号:637) 第一次
    • 2.找树左下角的值(题号:513) 第一次
    • 3.非递归实现二叉树的前序遍历(题号:144) 第一次
    • 4.非递归实现二叉树的后序遍历(题号:145) 第一次
    • 5.非递归实现二叉树的中序遍历(题号:94) 第0次
  • 四、“树”题目--二叉查找树
    • 1.修剪二叉搜索树(题号:669) 第1次
    • 2.二叉搜索树中第K小的元素(题号:230) 第1次
    • 3.把二叉搜索树转换为累加树(题号:538) 第1次
    • 4.二叉搜索树的最近公共祖先(题号:235) 第1次
    • 5.将有序数组转换为二叉搜索树(题号:108) 第1次
    • 6.有序链表转换二叉搜索树(题号:109) 第0次
    • 7.两数之和 IV - 输入 BST(题号:653) 第0次
    • 8.二叉搜索树的最小绝对差(题号:530) 第1次
    • 9.二叉树的最近公共祖先(题号:236) 第1次

一、“树”基础(来自LeetCode)

树的深度:某节点的深度是指从根节点到该节点的最长简单路径边的条数,从根节点往下数边数。
树的高度:某节点的高度指从该节点到叶子节点的最长简单路径边的条数,从叶子节点往上数。

二、“树”题目–递归

1.二叉树的最大深度(题号:104,Easy) 第2次

题目描述
给定一个二叉树,找出其最大深度,二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
LeetCod--树_第1张图片
解题思路:利用递归的思想,三部曲:第一步,找到递归出口,当root为0时,返回0,即为递归出口;第二步,找返回值,返回值为int型,为本子树的深度;第三步:递归主体是左右子树的深度,并进行比较。可参考:https://blog.csdn.net/weixin_43502661/article/details/90743053
代码

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
        int l = maxDepth(root.left) + 1;
        int r = maxDepth(root.right) + 1;
        return Math.max(l,r);
    }
}

2.平衡二叉树

题目描述:给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
LeetCod--树_第2张图片
LeetCod--树_第3张图片
解题思路:利用递归的思路,只不过要用两个函数,同样遵循递归三部曲,只不过这里的第三步递归函数的主体增加了判断该级树是否为平衡二叉树的步骤。
启发:递归函数并不一定是要用一个函数完成(尤其是对于返回boolean类型值的函数),也可以使用返回值为其他类型(比如int型)来进行递归。
代码

class Solution {
    
    private boolean result = true; 
    public boolean isBalanced(TreeNode root) {
        MaxDepth(root);
        return result;
    }
    
    public int MaxDepth(TreeNode root){
        if(root == null){
            return 0;
        }
        int l = MaxDepth(root.left);
        int r = MaxDepth(root.right);
        
        if(Math.abs(l-r) > 1) this.result = false;
        return Math.max(l+1,r+1);
    }  
}

3.二叉树的直径

二叉树的直径
题目描述:给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。
LeetCod--树_第4张图片
解题思路:根据二叉树最大深度的代码可以得到每一个子树的左右深度(分别用l和r表示),将某由于深度指的是根节点到叶子节点的节点的数目,这里需要统计的是边数,所以对于某一个子树,它的直径为左右最大深度对应的边数之和,即(l-1+r-1),定义一个成员变量len初始化为0,然后在不断递归的过程中进行比较,得到其最大值。
代码

class Solution {
    public int len = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        maxDepth(root);
        return len;
        
    }
    
    public int maxDepth(TreeNode root){
        if(root == null){
            return 0;
        }
        
        int l = maxDepth(root.left) + 1;
        int r = maxDepth(root.right) + 1;

        len = (len < (l+r-2)) ? (l+r-2) : len;
        return Math.max(l,r);
    }
}

4.路径总和

路径总和
题目描述:给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
LeetCod--树_第5张图片
解题思路:采用递归的思路,将这颗树看成一个只包含:左、右、根节点,可以看成从根节点开始遍历,每过一个根节点,则sum减去根节点的值,最后到叶子节点时判断sum是否为0,也即找到递归的出口(遍历到叶子节点即为递归出口,这里有两个出口,出口值分别为false和true)。
代码
参考代码:优秀

public boolean hasPathSum(TreeNode root, int sum) {
    if (root == null) return false;
    if (root.left == null && root.right == null && root.val == sum) return true;
    return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}

我的代码:垃圾

class Solution {
    private boolean result=false;
    public boolean hasPathSum(TreeNode root, int sum) {
        if(root == null){
            return false;
        }
        path(root,sum);
        return result;
    }
    
    public void path(TreeNode root,int sum){
        if(root.left == null && root.right == null){
            sum = sum - root.val;
            if(sum == 0){
                result = true;
            }
        }
        
        if(root.left != null){
            path(root.left,sum - root.val);
        }
        
        if(root.right != null){
            path(root.right,sum - root.val);
        }
    }
}

5.合并二叉树

合并二叉树
题目描述:(题号:617)给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
LeetCod--树_第6张图片

解题思路:利用迭代的思想,三部曲,第一步:迭代出口,三种情况(t1和t2同时为空,t1为空、t2为空)。第二步:返回值为result。第三步:递归主体,
result.val = t1.val + t2.val;
result.left = mergeTrees(t1.left,t2.left);
result.right = mergeTrees(t1.right,t2.right);
代码

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 result = t1;
        result.val = t1.val + t2.val;
        result.left = mergeTrees(t1.left,t2.left);
        result.right = mergeTrees(t1.right,t2.right);
        return result;
    }
}

6.翻转二叉树

翻转二叉树第2次
题目描述:翻转一棵二叉树。
LeetCod--树_第7张图片
解题思路:利用递归的思想,三部曲,第一步:递归出口,当传入的节点为null时,返回null;第二步:返回值,返回传入的root节点,第三步:递归方法主体,将root的左子树先暂存下来,然后让root的左子树等于其右子树,再让右子树等于暂存的左子树;
代码

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

    }
}

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

统计路径和等于一个数的路径数量
题目描述:给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
LeetCod--树_第8张图片
解题思路:由于这道题没有限制从头节点开始到哦叶子节点终止,解决办法是:将一颗包含(root,left,right)的一棵树,分别考虑以三个节点开始的情况,从root节点开始的情况,直接采用从头节点开始遍历,采用sum-root.val的方法,找到路径等于sum的个数,在以非头节点开始的情况,则采用双重递归的方式,将root.left、root.right重新当作新的root节点进行递归。
代码

class Solution {
    public int pathSum(TreeNode root, int sum) {
        if(root == null){
            return 0;
        }
        int num = start_path(root,sum) + pathSum(root.left, sum) + pathSum(root.right,sum);
        return num;
    }
    
    public int start_path(TreeNode root,int sum){
        if(root == null){
            return 0;
        }
        int ret = 0;
        if(root.val == sum){
            ret++;
        }
        ret += start_path(root.left,sum - root.val) + start_path(root.right,sum - root.val);
        return ret;
    }
}

8.另一个树的子树(题号:572)

另一个树的子树
题目描述:给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
LeetCod--树_第9张图片
LeetCod--树_第10张图片
解题思路:利用双重递归的思路,首先将树看成root、left、right三个节点。在第一重递归,递归三部曲,第一步:当s为null或者t为null时,返回false;第二步:递归主体,将以s为根节点的树与以t为根节点的树进行比较,同时比较以s.left和s.right为根节点的树与t树进行比较;第三步:返回比较结果,三者的比较是或的关系。在第二重递归,将使用递归遍历的方式,对两棵树进行比较。
代码
参考代码:优秀

public boolean isSubtree(TreeNode s, TreeNode t) {
    if (s == null) return false;
    return isSubtreeWithRoot(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t);
}

private boolean isSubtreeWithRoot(TreeNode s, TreeNode t) {
    if (t == null && s == null) return true;
    if (t == null || s == null) return false;
    if (t.val != s.val) return false;
    return isSubtreeWithRoot(s.left, t.left) && isSubtreeWithRoot(s.right, t.right);
}

我的代码:垃圾

class Solution {
    public boolean isSubtree(TreeNode s, TreeNode t) {
        if(s == null || t == null){
            return false;
        }
        boolean result1 = bijiao(s,t);
        if(result1 == true){
            return true;
        }
        return isSubtree(s.left,t)||isSubtree(s.right,t);
    }
    
    private boolean bijiao(TreeNode s, TreeNode t){
        if(s == null && t == null) return true;
        if(s == null || t == null){
            return false;
        }
        
        boolean result = false;
        if(s.val == t.val){
            result =  bijiao(s.left,t.left)&&bijiao(s.right,t.right);
        }
        return result;
    }
    
}

9.对称二叉树(题号:101)

对称二叉树
题目描述:给定一个二叉树,检查它是否是镜像对称的,
LeetCod--树_第11张图片
LeetCod--树_第12张图片
解题思路:直接使用递归比较就行,设root的左子节点为t1,右子节点为t2,调用递归函数进行比较,比较t1.left与t2.right,比较t1.right与t2.left,由此往下递归,得到的结果取&&运算。
代码
参考代码:优秀!!!

public boolean isSymmetric(TreeNode root) {
    if (root == null) return true;
    return isSymmetric(root.left, root.right);
}

private boolean isSymmetric(TreeNode t1, TreeNode t2) {
    if (t1 == null && t2 == null) return true;
    if (t1 == null || t2 == null) return false;
    if (t1.val != t2.val) return false;
    return isSymmetric(t1.left, t2.right) && isSymmetric(t1.right, t2.left);
}

我的代码:很垃圾,将其中一个子树翻转,再比较,多此一举

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return true;
        }
        return bijiao(root.left,overturn(root.right));
        
    }
    private TreeNode overturn(TreeNode root){
        if(root == null){
            return null;
        }
        TreeNode node = overturn(root.left);
        root.left = overturn(root.right);
        root.right = node;
        return root;
    }
    
    private boolean bijiao(TreeNode l,TreeNode r){
        if(l == null && r == null){
            return true;
        }
        if(l == null || r == null){
            return false;
        }
        
        if(l.val != r.val){
            return false;
        }
        return bijiao(l.left,r.left) && bijiao(l.right,r.right);
    }
}

10.二叉树的最小深度

二叉树的最小深度(题号:111) 第2次
题目描述:给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
解题思路:还是迭代的思想,与二叉树最大深度不同的是,这里需要考虑左右子节点为空的情况,比如左子节点为空,则其没有叶子节点,这时如果右子节点不为空,则继续最小深度在右子节点中,这里最关键的一步是判断root节点的左右子节点为空时的情况(如果某一个子节点为空,则返回另一个子节点的递归结果,若同时为空,返回1)。
代码
参考代码1:

public int minDepth(TreeNode root) {
    if (root == null) return 0;
    int left = minDepth(root.left);
    int right = minDepth(root.right);
    if (left == 0 || right == 0) return left + right + 1;
    return Math.min(left, right) + 1;
}

我修改的代码2:主要区别在于加减1的方式,

class Solution {
   public int minDepth(TreeNode root) {
        if (root == null) return 0;
        int left = minDepth(root.left)+1;
        int right = minDepth(root.right)+1;
        if (left == 1 || right == 1) return Math.max(left,right);
        return Math.min(left, right);
    }
}

我的实现代码(2020.1.1):

class Solution {
    public int minDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
        if(root.left == null && root.right == null){
            return 1;
        }
        else if(root.left == null){
            return minDepth(root.right)+1;
        }
        else if(root.right == null){
            return minDepth(root.left)+1;
        }
        
        return Math.min(minDepth(root.left),minDepth(root.right))+1;
        
    }
}

11.左叶子之和(题号:404) 第1次

左叶子之和
题目描述:计算给定二叉树的所有左叶子之和。
LeetCod--树_第13张图片
解题思路:采用递归的思想,三部曲,第一步:找到递归的出口,即让根节点为空是,返回0;第二步:返回值,对于一颗简单树(包含root,left,right)来说,返回“left的左叶子和”+“right的左叶子和”,如果root.left为叶子节点,则返回root.left+“right的左叶子和”。
代码
我的代码:优秀(在sumOfLeftLeaves函数中直接判断左子节点是否为叶子节点,并引入变量num来代表左叶子节点的值)

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if(root == null){
            return 0;
        }
        int num = 0;
        if(root.left != null){
            if(root.left.left == null && root.left.right == null)
                num = root.left.val;
        }
        int l = sumOfLeftLeaves(root.left);
        int r = sumOfLeftLeaves(root.right);  
        return l+r+num;
    }
}

参考代码:同样优秀(将判断是否为左叶子节点单列一个函数,并采用标准的思维方式编写代码)

public int sumOfLeftLeaves(TreeNode root) {
    if (root == null) return 0;
    if (isLeaf(root.left)) return root.left.val + sumOfLeftLeaves(root.right);
    return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}

private boolean isLeaf(TreeNode node){
    if (node == null) return false;
    return node.left == null && node.right == null;
}

12.最长节点值相同的路径(题号:687) 有待进一步理解???

最长节点值相同的路径
题目描述
给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。
注意:两个节点之间的路径长度由它们之间的边数表示。
LeetCod--树_第14张图片
LeetCod--树_第15张图片
解题思路
这道题采用由下到上(从叶子节点到根节点)的思路会更加清晰,首先,假设一棵树包含三个节点(root、left、right),如果left.val与right.val、root.val想等,这是暂存路径长度path为2,但是返回到上层只能返回1,因为从上层节点到这一层的root之后,只能向左或者向右走,所以取左节点或者右节点路径的最大值,当然,也就是说函数的返回值为向左或向右的最大值。
代码

class Solution {
    private int path = 0;
    public int longestUnivaluePath(TreeNode root) {
        numpath(root);
        return path;
    }
    
    private int numpath(TreeNode root){
        if(root == null){
            return 0;
        }
        int left = numpath(root.left);
        int right = numpath(root.right);
        int leftpath = root.left != null && root.val == root.left.val ? left + 1 : 0;
        int rightpath = root.right != null && root.val == root.right.val ? right + 1 : 0;
        path = Math.max(path,leftpath + rightpath);
        return Math.max(leftpath,rightpath);
    }
}

13.打家劫舍 III,间隔遍历(题号:337,Medium) 第二遍

打家劫舍 III
题目描述
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
LeetCod--树_第16张图片
LeetCod--树_第17张图片
解题思路
代码

class Solution {

    public int rob(TreeNode root){
        if(root == null){
            return 0;
        }
        int sum = 0;
        sum = sum + root.val;
        if(root.left != null){
             sum = sum + rob(root.left.left)+rob(root.left.right);
        }
        if(root.right != null){
             sum = sum + rob(root.right.left)+rob(root.right.right);
        }
       return Math.max(sum,rob(root.left)+rob(root.right));
    }

}

参考代码:1ms,击败100%用户

  class Solution {
    public int rob(TreeNode root) {
        int[] res = doRob(root);
        return Math.max(res[0],res[1]);
    }
    //res[0]为不包括根节点的最大值,res[1]为包括根节点的最大值
    private int[] doRob(TreeNode root){
        int[] res = new int[2];
        if(root == null)
            return res;
        int[] left = doRob(root.left);
        int[] right = doRob(root.right);
        //不包含根节点,最大值为两个子树的最大值之和
        res[0] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
        //包含根节点,最大值为两个子树不包含根节点的最大值加上根节点的值
        res[1] = left[0] + right[0] + root.val;
        return res;
    }
}  

14.二叉树中第二小的节点(题号:671) 第一遍

二叉树中第二小的节点
题目描述
给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值。给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。
LeetCod--树_第18张图片
LeetCod--树_第19张图片
解题思路:考虑从上到下的一种递归思路,因为叶子节点肯定都是大于等于root节点的,所以可以将root节点的左右子节点中与root.val不相同的子节点暂存(作为备选A),将与root.val相同的子节点(记为节点B)继续向下遍历,因为比root.val大同时比备选A小的叶子节点只能在B节点的子节点中出现,然后递归找到B子树下面的除root.val之外的次小节点值,再与备选A进行比较,得到次小值。
代码
参考代码:

class Solution {
    public int findSecondMinimumValue(TreeNode root) {
        if (root == null) return -1;
        if (root.left == null && root.right == null) return -1;
        int leftVal = root.left.val;
        int rightVal = root.right.val;
        if (leftVal == root.val) leftVal = findSecondMinimumValue(root.left);
        if (rightVal == root.val) rightVal = findSecondMinimumValue(root.right);
        if (leftVal != -1 && rightVal != -1) return Math.min(leftVal, rightVal);
        if (leftVal != -1) return leftVal;
        return rightVal;
    }

}

15.相同的树(题号:100) 第1次

题目链接:相同的树
题目描述
给定两个二叉树,编写一个函数来检验它们是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
LeetCod--树_第20张图片
代玛:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if(p == null && q == null){
            return true;
        }
        else if(p != null && q != null){
            if(p.val == q.val)
                return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
            else 
                return false;
        }
        return false;
        
    }
}

16.求根到叶子节点数字之和(题号:129) 第1次

题目链接:求根到叶子节点数字之和
题目描述
给定一个二叉树,它的每个结点都存放一个 0-9 的数字,每条从根到叶子节点的路径都代表一个数字。
例如,从根到叶子节点路径 1->2->3 代表数字 123。
计算从根到叶子节点生成的所有数字之和。

说明: 叶子节点是指没有子节点的节点。
LeetCod--树_第21张图片
LeetCod--树_第22张图片
解题思路:利用递归的思路,另外写一个返回值位int型,并且多一个入参val的函数,val代表高位,需要乘以10,再加上当前root.val值,递归的出口为叶子节点所对应的最简单的一颗二叉树,即return val*10+root.val。
我的代码

class Solution {
    public int sumNumbers(TreeNode root) {
        if(root == null)
            return 0;
        if(root.left == null && root.right == null)
            return root.val;
        return sumNumbers(root.left,root.val)+sumNumbers(root.right,root.val);
    }
    
    public int sumNumbers(TreeNode root,int val){
        if(root == null)
            return 0;
        if(root.left == null && root.right == null)
            return val*10+root.val;
        
        val = val*10 + root.val;
        int l = sumNumbers(root.left,val);
        int r = sumNumbers(root.right,val);
        
        return l+r;
        
        
    }
}
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {    //2020.4.30代码实现
    private int sum = 0;
    public int sumNumbers(TreeNode root) {
        if(root == null)
            return 0;
        
        Numbers(0,root);
        return sum;

    }
    public void Numbers(int s, TreeNode root){
        int l = s;
        int r = s;
        if(root.left == null && root.right == null){
            sum = sum + s*10 + root.val;
        }
        
        if(root.left != null){
            l = l*10 + root.val;
            Numbers(l,root.left);
        }
        
        if(root.right != null){
            r = r*10 + root.val;
            Numbers(r,root.right);
        }
    }
}

17.二叉树的所有路径(题号:257) 第1次

题目链接:二叉树的所有路径
题目描述
给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。
LeetCod--树_第23张图片
解题思路
代码

class Solution {
  
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> list = new ArrayList<String>();
        if(root == null){
            return list;
        }
        if(root.left == null && root.right == null){
            list.add(root.val+"");
            return list;
        }
        List<String> list_left = binaryTreePaths(root.left);
        for(String s : list_left){
            list.add(root.val+"->"+s);
        }
        
        List<String> list_right = binaryTreePaths(root.right);
        for(String s : list_right){
            list.add(root.val+"->"+s);
        }
        
        return list;
    }
}
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {    //2020.4.30更新
    List<String> list = new ArrayList<String>();
    public List<String> binaryTreePaths(TreeNode root) {
        String res = "";
        TreePath(res,root);
        return list;
    }
    
    public void TreePath(String result,TreeNode root){
        String s1 = result;
        String s2 = result;
        if(root == null)
            return ;
        if(root.left == null && root.right == null)
            list.add(result+root.val);
        
        if(root.left != null) {
            s1 = s1  + root.val + "->";
            TreePath(s1,root.left);
        }
        
        if(root.right != null) {
            s2 = s2  + root.val + "->";
            TreePath(s2,root.right);
        }
            
    }
}

三、“树”题目–遍历

1.二叉树的层平均值(题号:637) 第一次

题目链接:二叉树的层平均值
题目描述
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
LeetCod--树_第24张图片

解题思路

代码

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

2.找树左下角的值(题号:513) 第一次

题目链接:找树左下角的值
题目描述:给定一个二叉树,在树的最后一行找到最左边的值。
LeetCod--树_第25张图片
LeetCod--树_第26张图片
解题思路:充分利用队列的先入先出的思想,使用while循环,将最不可能的结果最先进入队列,也就是一次进队的为root,然后root出队,root.right、root.left依次进队,最后while循环结束运行之后的最后一次出队的节点即为最左下角的值。
代码
参考代码:优秀

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

我的代码:按照从左到右的一般顺序进行遍历,将最后一层遍历出来之后,取最后一层队列的第一个值。垃圾!

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList();
        queue.add(root);
        TreeNode result = root;
        while(!queue.isEmpty()){
            int size = queue.size();
            result = queue.peek();
            for(int i = 0; i < size ;i++){
                TreeNode node = queue.poll();
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            } 
        }
        return result.val;
    }
}

3.非递归实现二叉树的前序遍历(题号:144) 第一次

题目描述
给定一个二叉树,返回它的前序遍历。
LeetCod--树_第27张图片
解题思路:定义一个栈,首先将root节点压入s1栈中,然后用while循环,将s1栈中的节点node弹出,并判断node是否有左右子节点,若有,现将右子节点压入栈中,再将左子节点压入栈中,然后将弹出的node节点的val值添加到数组list中,进行下一次循环,直到s1中为空为止。
代码
非递归实现方式:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        if(root == null) return list;
        s1.push(root);
        while(!s1.isEmpty()){
            TreeNode node = s1.pop();
            if(node.right != null) s1.push(node.right);
            if(node.left != null) s1.push(node.left);
            
            list.add(node.val);
        }
        return list;
    }
}

递归实现方式:

class Solution {
    private List<Integer> list = new ArrayList<Integer>();
    public List<Integer> preorderTraversal(TreeNode root) {
        
        if(root == null){
            return list;
        }
        list.add(root.val);
        preorderTraversal(root.left);
        preorderTraversal(root.right);        
        return list;        
    }
}

4.非递归实现二叉树的后序遍历(题号:145) 第一次

题目描述
解题思路
代码
我的代码:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
         
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        Stack<TreeNode> s2 = new Stack<TreeNode>();
        List<Integer> ret = new ArrayList<Integer>();
        if(root == null) return ret;
        s1.push(root);
        if(root.left != null){
            s2.push(root.left);
        }        
        if(root.right != null){
            s2.push(root.right);
        }

        while(!s2.isEmpty()){
            TreeNode node = s2.pop();
            s1.push(node);
            if(node.left != null) s2.push(node.left);
            if(node.right != null) s2.push(node.right);
        }
        while(!s1.isEmpty()){
            ret.add(s1.pop().val);
        }
        return ret;
                
    }
}

5.非递归实现二叉树的中序遍历(题号:94) 第0次

四、“树”题目–二叉查找树

1.修剪二叉搜索树(题号:669) 第1次

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

解题思路
代码

class Solution { 
    public TreeNode trimBST(TreeNode root, int L, int R){
        if(root == null) return null;
        if(root.val < L){
            root = trimBST(root.right,L,R);
        }
        else if(root.val > R){
            root = trimBST(root.left,L,R);
        }
        else {
            if(root.left != null) root.left = trimBST(root.left,L,R);
            if(root.right != null) root.right = trimBST(root.right,L,R);
        }
        return root;
    }
}

2.二叉搜索树中第K小的元素(题号:230) 第1次

题目描述
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。
LeetCod--树_第30张图片
LeetCod--树_第31张图片
解题思路
我的思路:二叉查找树中第k小的节点也即中序遍历后得到的第k个节点,利用递归中序遍历的思路,可以得到递归的结果,将结果添加到数组链表ArrayList中,再使用get方法获取第k小的值。(我实现的代码效率较低
参考思路:也是利用中序遍历,但是不将遍历到的从小到大的数据存放到链表中,而是遍历到后就不管了,等到找到符合要求的第k小值,再将其保存到result变量。
代码
我的代码:

class Solution {  
    public int kthSmallest(TreeNode root, int k) {
        List<Integer> list = new ArrayList<Integer>();
        find(root,list);
        int result = list.get(k-1);
        
        return result;
    }
    private void find(TreeNode root, List<Integer> list){
        if(root == null){
            return ;
        }
        find(root.left,list);
        list.add(root.val);
        find(root.right,list);
    }
}

参考代码:

class Solution {  
    private int result = 0;
    private int cnt = 0;
    public int kthSmallest(TreeNode root, int k) {
        find(root,k);
        
        return result;
    }
    private void find(TreeNode root,int k){
        if(root == null){
            return ;
        }
        find(root.left,k);
        cnt++;
        if(k == cnt){
            result = root.val;
            return ;
        }            
        find(root.right,k);
    }
}

3.把二叉搜索树转换为累加树(题号:538) 第1次

题目描述
给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。
LeetCod--树_第32张图片
解题思路:由于二叉搜索树
代码

class Solution {
    private int sum = 0;
    public TreeNode convertBST(TreeNode root) {
        if(root == null){
            return root;
        }
        if(root.right != null) convertBST(root.right);
        sum = sum + root.val;
        root.val = sum;
        if(root.left != null) convertBST(root.left);
        return root;
    }
}

4.二叉搜索树的最近公共祖先(题号:235) 第1次

题目链接:二叉搜索树的最近公共祖先
题目描述
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
LeetCod--树_第33张图片
解题思路
代码

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) 
            return null;
        if(root.val > p.val && root.val > q.val) root = lowestCommonAncestor(root.left,p,q);
        if(root.val < p.val && root.val < q.val) root = lowestCommonAncestor(root.right,p,q);
        return root;     
    }
}

5.将有序数组转换为二叉搜索树(题号:108) 第1次

题目链接:将有序数组转换为二叉搜索树
题目描述
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
LeetCod--树_第34张图片
解题思路:这里答案不唯一,比如数组长度为偶数6,此时可以让第3个或者第4个数作为根节点的值,然后往后递归,若数组长度为奇数,则直接让中间的那个数作为root节点的值。
代码

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return createTree(nums,0,nums.length-1);
    }
    
    public TreeNode createTree(int[] nums,int l,int r){
        if(l > r) 
            return null;
        int index = (l+r)/2;
        TreeNode root = new TreeNode(nums[index]);
        root.left = createTree(nums,l,index-1);
        root.right = createTree(nums,index+1,r);
        return root;
    }
}

6.有序链表转换二叉搜索树(题号:109) 第0次

题目链接:有序链表转换二叉搜索树
题目描述:给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
LeetCod--树_第35张图片
解题思路
代码

7.两数之和 IV - 输入 BST(题号:653) 第0次

题目链接:两数之和 IV - 输入 BST
题目描述
给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
LeetCod--树_第36张图片
LeetCod--树_第37张图片
解题思路
代码

class Solution {
    public boolean findTarget(TreeNode root, int k) {
        List<Integer> list = new ArrayList<Integer>();
        find(list,root);
        for(int i = 0; i < list.size(); i++){
            for(int j = 0; j < list.size(); j++){
                if(i != j && k == (list.get(i) + list.get(j))){
                    return true;
                }
            }
        }
        return false;
        
    }
    
    public void find(List<Integer> list,TreeNode root){
        if(root == null){
            return ;
        }
        find(list,root.left);
        list.add(root.val);
        find(list,root.right);
    }
}

8.二叉搜索树的最小绝对差(题号:530) 第1次

题目链接:二叉搜索树的最小绝对差
题目描述
给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值。
LeetCod--树_第38张图片
解题思路
代码
我的代码:比较垃圾

class Solution {
    public int getMinimumDifference(TreeNode root) {
        ArrayList<Integer> array = new ArrayList<Integer>();
        find(array,root);
        int index = 0;
        int min = array.get(array.size()-1);
        while(index < array.size() - 1){
            min = Math.min(min,Math.abs(array.get(index) - array.get(index + 1)));
            index++;
        }
        return min;
        
    }
    
    public void find(ArrayList<Integer> array,TreeNode root){
        if(root == null){
            return ;
        }
        find(array,root.left);
        array.add(root.val);
        find(array,root.right);        
    }
}

9.二叉树的最近公共祖先(题号:236) 第1次

题目链接:二叉树的最近公共祖先
代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root== null)
            return root;
        if(root == p || root == q){
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        
        if(left != null && right != null)
            return root;
        else if(left != null)
            return left;
        else if(right != null)
            return right;
        
        return null;
        
    }
}

你可能感兴趣的:(LeetCode)