LeetCode精选题之树

LeetCode精选题之树

参考资料:CyC2018的LeetCode题解

总结:

  1. 二叉树具有天然的递归特性,对于一棵二叉树必须遍历整棵树才能考虑全部的情况,所以遇到二叉树的题目应该首先考虑递归解法(下面的所有题目都是用递归来解决的)。对于BST,应该充分考虑它的特性,即它的节点之间是有大小关系的,正是由于大小关系,所以中序遍历在BST的题目尤为常见,比如下面序号2(LeetCode230)、 9 (LeetCode530)、10(LeetCode501)等。
  2. 对于二叉树的递归调用问题,一定要深刻明白递归函数的语义,一定要站在这个二叉树的根节点的角度去考虑,想像root的左子树和右子树是另外的一棵二叉树(用三角形来代替)接在root的左右两边,这样想问题的好处是可以理清代码的书写思路,不至于陷入递归的调用细节(指的是root->root.left->root.left.left...)中去。
  3. 二叉树的常见遍历方式,前序、中序、后序、层序,递归和非递归解法都要熟悉。

递归解题

1 二叉树的最大深度–LeetCode104

给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。

/**
 * 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 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
    }
}

2 平衡二叉树–LeetCode110

给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

方法一:暴力法,从顶向下,但是会产生大量重复计算,时间复杂度较高。

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return isBalanced(root.left) 
            && isBalanced(root.right)
            && Math.abs(maxDepth(root.left)-maxDepth(root.right)) <= 1;
    }

    private int maxDepth(TreeNode root) {
        if (root == null) return 0;
        return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));
    }
}

方法二:从底向上。对二叉树做先序遍历,从底至顶返回子树最大高度,若判定某子树不是平衡树则 “剪枝” ,直接向上返回。

class Solution {
    public boolean isBalanced(TreeNode root) {
        return maxDepth(root) != -1;
    }

    private int maxDepth(TreeNode root) {
        if (root == null) return 0;
        int leftDepth = maxDepth(root.left);
        if (leftDepth == -1) return -1;
        int rightDepth = maxDepth(root.right);
        if (rightDepth == -1) return -1;
        return Math.abs(leftDepth-rightDepth) < 2 ? 1+Math.max(leftDepth, rightDepth) : -1;
    }
}

3 二叉树的直径–LeetCode543

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

示例 :

给定二叉树:
          1
         / \
        2   3
       / \     
      4   5    
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

注意:两结点之间的路径长度是以它们之间边的数目表示。

class Solution {
    private int max = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        maxDepth(root);
        return max;
    }
    // 从底向上,计算每个节点,经过它的的最大路径,最后max得到了整棵树最大的路径
    private int maxDepth(TreeNode node) {
        if (node == null) return 0;
        int leftDepth = maxDepth(node.left);
        int rightDepth = maxDepth(node.right);
        max = Math.max(max, leftDepth+rightDepth);
        return 1 + Math.max(leftDepth, rightDepth);
    }
}

4 翻转二叉树–LeetCode226

翻转一棵二叉树。

示例:
输入:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

输出:

     4
   /   \
  7     2
 / \   / \
9   6 3   1

代码如下:

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

5 合并二叉树–LeetCode617

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

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

示例 1:

输入: 
	Tree 1                     Tree 2                  
          1                         2                             
         / \                       / \                            
        3   2                     1   3                        
       /                           \   \                      
      5                             4   7                  
输出: 
合并后的树:
	     3
	    / \
	   4   5
	  / \   \ 
	 5   4   7

注意: 合并必须从两个树的根节点开始。

自己写的代码,根据题目我的思路是将t2合并到t1上,合并的过程是不断判断t1t2的左右子树是否为空的情况。

class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if (t1 == null) return t2;
        if (t2 == null) return t1;

        t1.val += t2.val;
        mergeTreesCore(t1, t2);
        return t1;
    }

    private void mergeTreesCore(TreeNode t1, TreeNode t2) {
        if (t1.left != null) {
            if (t2.left != null) {
                t1.left.val += t2.left.val;
                mergeTreesCore(t1.left, t2.left);
            }else {
                //t2.left为空就合并完成
            }
        }else {
            if (t2.left != null) {
                t1.left = new TreeNode(t2.left.val);
                mergeTreesCore(t1.left, t2.left);
            }
        }

        if (t1.right != null) {
            if (t2.right != null) {
                t1.right.val += t2.right.val;
                mergeTreesCore(t1.right, t2.right);
            }
        }else {
            if (t2.right != null) {
                t1.right = new TreeNode(t2.right.val);
                mergeTreesCore(t1.right, t2.right);
            }
        }
    }
}

参考大佬的思路写的代码,将t1t2合并成一颗新树:

class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        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 路径总和–LeetCode112

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

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2

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

7 路径总和III–LeetCode437**

给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

返回 3。和等于 8 的路径有:

1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11

代码如下:

class Solution {
    // 在以root为根节点的二叉树中,寻找和为sum的路径,返回这样的路径个数
    public int pathSum(TreeNode root, int sum) {
        if (root == null) {
            return 0;
        }
        int res = findPath(root, sum);
        res += pathSum(root.left, sum);
        res += pathSum(root.right, sum);
        return res;
    }

    // 在以root为根节点的二叉树中,寻找一条包含root的路径,使得路径和为sum
    private int findPath(TreeNode root, int sum) {
        if (root == null) {
            return 0;
        }
        int res = 0;
        if (root.val == sum) {
            res += 1;// 这里不能直接返回,因为元素值可能为负数,所以2 1 -1三数相加依旧为2
        }

        res += findPath(root.left, sum-root.val);
        res += findPath(root.right, sum-root.val);

        return res;
    }
}

8 另一个数的子树–LeetCode572

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

示例 1:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2

给定的树 t:

   4 
  / \
 1   2

返回 true,因为 t 与 s 的一个子树拥有相同的结构和节点值。

示例 2:
给定的树 s:

     3
    / \
   4   5
  / \
 1   2
    /
   0

给定的树 t:

   4
  / \
 1   2

返回 false。

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

    }

    // 包含根节点s,看s中是否存在子树和t相等
    private boolean isSubtreeWithRoot(TreeNode s, TreeNode t) {
        if (s == null && t == null) {
            return true;
        }
        if (s == null || t == null) {
            return false;
        }
        if (s.val != t.val) {
            return false;
        }

        return isSubtreeWithRoot(s.left, t.left) && isSubtreeWithRoot(s.right, t.right);
    }
}

9 对称二叉树–LeetCode101

给定一个二叉树,检查它是否是镜像对称的。例如,二叉树 [1,2,2,3,4,4,3]是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面这个[1,2,2,null,3,null,3]则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

进阶:你可以运用递归和迭代两种方法解决这个问题吗?

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

    private boolean isSymmetric(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 isSymmetric(l.left, r.right) && isSymmetric(l.right, r.left);
    }
}

10 二叉树的最小深度–LeetCode111

给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。说明: 叶子节点是指没有子节点的节点。

示例:

给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最小深度 2.

class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }

        if (root.left != null && root.right != null) {
            return 1 + Math.min(minDepth(root.left), minDepth(root.right));
        }else if (root.left == null) {
            return 1 + minDepth(root.right);
        }else {
            return 1 + minDepth(root.left);
        }
    }
}

11 左叶子之和–LeetCode404

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

示例:

    3
   / \
  9  20
    /  \
   15   7
在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

代码如下:

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

12 最长同值路径–LeetCode687**

给定一个二叉树,找到最长的路径,这个路径中的每个节点具有相同值。 这条路径可以经过也可以不经过根节点。注意:两个节点之间的路径长度由它们之间的边数表示。

示例 1:
输入:

              5
             / \
            4   5
           / \   \
          1   1   5

输出:

2

示例 2:
输入:

              1
             / \
            4   5
           / \   \
          4   4   5

输出:

2

注意: 给定的二叉树不超过10000个结点。 树的高度不超过1000。

class Solution {
    private int path = 0;
    public int longestUnivaluePath(TreeNode root) {
        dfs(root);
        return path;
    }
    // 以root为根的二叉树中,包含root节点,从root向下的同值路径的长度
    private int dfs(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = dfs(root.left);
        int right = dfs(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–LeetCode337

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

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:

输入: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

输出: 7 
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

示例 2:

输入: [3,4,5,1,3,null,1]

     3
    / \
   4   5
  / \   \ 
 1   3   1

输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.

这个是间隔遍历的问题,使用HashMap来保存中间计算结果,避免重复计算。

import java.util.HashMap;
class Solution {
    public int rob(TreeNode root) {
        HashMap<TreeNode, Integer> map = new HashMap<>();
        return robCore(root, map);
    }

    private int robCore(TreeNode root, HashMap<TreeNode, Integer> map) {
        if (root == null) {
            return 0;
        }
        if (map.containsKey(root)) {
            return map.get(root);
        }
        int money = root.val;
        if (root.left != null) {
            money += (robCore(root.left.left, map) + robCore(root.left.right, map));
        }
        if (root.right != null) {
            money += (robCore(root.right.left, map) + robCore(root.right.right, map));
        }
        money = Math.max(money, robCore(root.left, map)+robCore(root.right, map));
        map.put(root, money);
        return money;
    }
}

14 二叉树中第二小的节点–LeetCode671**

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

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

示例 1:

输入: 
    2
   / \
  2   5
     / \
    5   7

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

示例 2:

输入: 
    2
   / \
  2   2

输出: -1
说明: 最小的值是 2, 但是不存在第二小的值。

代码如下:

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不是左子树的第二小,因此需要在左子树里面继续寻找第二小
            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 rightVal;
        }
        return leftVal;
    }
}

BST相关

1 修剪二叉查找树–LeetCode669

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

示例 1:

输入: 
    1
   / \
  0   2

  L = 1
  R = 2

输出: 
    1
      \
       2

示例 2:

输入: 
    3
   / \
  0   4
   \
    2
   /
  1

  L = 1
  R = 3

输出: 
      3
     / 
   2   
  /
 1

递归实现:

class Solution {
    public TreeNode trimBST(TreeNode root, int L, int R) {
        if (root == null) {
            return null;
        }

        if (root.val < L) {
            return trimBST(root.right, L, R);
        }else if (root.val > R) {
            return trimBST(root.left, L, R);
        }else {
            root.left = trimBST(root.left, L, R);
            root.right = trimBST(root.right, L, R);
            return root;
        }
    }
}

2 二叉搜索树中第K小的元素–LeetCode230

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

说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。

示例 1:

输入: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
输出: 1

示例 2:

输入: root = [5,3,6,2,4,null,null,1], k = 3
       5
      / \
     3   6
    / \
   2   4
  /
 1
输出: 3

进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数?

中序遍历:

class Solution {
    private int cnt = 0;
    private int val = 0;
    public int kthSmallest(TreeNode root, int k) {
        inOrder(root, k);
        return val;
    }

    private void inOrder(TreeNode node, int k) {
        if (node == null) {
            return;
        }
        inOrder(node.left, k);
        cnt++;
        if (cnt == k) {
            val = node.val;
            return;
        }
        inOrder(node.right, k);
    }
}

递归解法:

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        int leftCnt = count(root.left);
        if (leftCnt == k-1) {
            return root.val;
        }else if (leftCnt > k-1) {
            return kthSmallest(root.left, k);
        }else {
            return kthSmallest(root.right, k - leftCnt - 1);
        }
    }

    private int count(TreeNode node) {
        if (node == null) {
            return 0;
        }
        return 1 + count(node.left) + count(node.right);
    }
}

3 把二叉搜索树转换为累加树–LeetCode538

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

例如:

输入: 原始二叉搜索树:
              5
            /   \
           2     13

输出: 转换为累加树:
             18
            /   \
          20     13

递归实现:

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

4 二叉搜索树的最近公共祖先–LeetCode235

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

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

5 二叉树的最近公共祖先–LeetCode236

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

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) {
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        return left == null ? right : (right == null ? left : root);
    }
}

6 将有序数组转换为二叉搜索树–LeetCode108

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return sortedArrayToBST(nums, 0, nums.length-1);
    }
    private TreeNode sortedArrayToBST(int[] nums, int l, int r) {
        if (l > r) {
            return null;
        }
        int mid = (l+r)/2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = sortedArrayToBST(nums, l, mid-1);
        root.right = sortedArrayToBST(nums, mid+1, r);
        return root;
    }
}

7 有序链表转换二叉搜索树–LeetCode109

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。

思路:一种很直接的思路是通过链表生成对应的数组,按照上一题的方法来构建BST,但本题期望的做法应该是直接用链表来构建,原理和上一题是一样的,只是需要通过快慢指针寻找链表的中点和保存中点的前一个节点。

class Solution {
    public TreeNode sortedListToBST(ListNode head) {
        // 递归终止条件
        if (head == null) {
            return null;
        }
        // 只有一个节点的话,就不再分下去了
        if (head.next == null) {
            return new TreeNode(head.val);
        }
        // 通过快慢指针寻找链表的中点和保存中点的前一个节点
        ListNode prev = null;
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            prev = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        
        TreeNode root = new TreeNode(slow.val);
        prev.next = null;// 将前部分和后面断开
        root.left = sortedListToBST(head);
        root.right = sortedListToBST(slow.next);
        return root;
    }
}

8 两数之和IV-输出BST–LeetCode653

给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。

思路:使用中序遍历得到有序数组之后,再利用双指针对数组进行查找。

import java.util.List;
import java.util.ArrayList;
class Solution {
    public boolean findTarget(TreeNode root, int k) {
        List<Integer> list = new ArrayList<>();
        inOrder(root, list);
        int l = 0;
        int r = list.size()-1;
        while (l < r) {
            int sum = list.get(l) + list.get(r);
            if (sum == k) {
                return true;
            }else if (sum > k) {
                r--;
            }else {
                l++;
            }
        }
        return false;

    }
    private void inOrder(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
        return;
    }
}

错误的思路:没有考虑两个数分别在左右子树中的情况。

class Solution {
    public boolean findTarget(TreeNode root, int k) {
        if (root == null) {
            return false;
        }
        int diff = k - root.val;
        if (diff < root.val && contains(root.left, diff)) {
            return true;
        } 
        if (diff > root.val && contains(root.right, diff)) {
            return true;
        }
        return findTarget(root.left, k) || findTarget(root.right, k);
    }
    private boolean contains(TreeNode root, int num) {
        if (root == null) {
            return false;
        }
        if (root.val == num) {
            return true;
        }else if (root.val < num) {
            return contains(root.right, num);
        }else {
            return contains(root.left, num);        
        }
    }
}

9 二叉搜索树的最小绝对差–LeetCode530

给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。

class Solution {
    private int prev = -1;//中序遍历前一个节点的值
    private int diff = Integer.MAX_VALUE;
    public int getMinimumDifference(TreeNode root) {
        inOrder(root);
        return diff;
    }
    private void inOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        if (prev != -1) {
            diff = Math.min(diff, root.val-prev);
        }
        prev = root.val;
        inOrder(root.right);
        return;
    }
}

10 二叉搜索树中的众数–LeetCode501

给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。

假定 BST 有如下定义:

  • 结点左子树中所含结点的值小于等于当前结点的值
  • 结点右子树中所含结点的值大于等于当前结点的值
  • 左子树和右子树都是二叉搜索树

例如:
给定 BST [1,null,2,2],

   1
    \
     2
    /
   2

返回[2].

提示:如果众数超过1个,不需考虑输出顺序

进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)

import java.util.List;
import java.util.ArrayList;
class Solution {
    private TreeNode preNode = null;
    private int cnt = 1;
    private int maxCnt = 1;

    public int[] findMode(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        inOrder(root, list);
        int[] res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
        return res;
    }

    private void inOrder(TreeNode root, List<Integer> list) {
        if (root == null) {
            return ;
        }
        inOrder(root.left, list);
        if (preNode != null) {
            if (root.val == preNode.val) {
                cnt++;
            }else {
                cnt = 1;
            }
        }
        // 比较重复次数
        if (cnt > maxCnt) {
            maxCnt = cnt;
            list.clear();
            list.add(root.val);
        }else if (cnt == maxCnt) {
            list.add(root.val);
        }
        preNode = root;
        inOrder(root.right, list);
        return;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值