算法总结 - 树 - 传值

这篇博客探讨了在处理树结构问题时,如何通过传值策略解决涉及不同值传递的难题。博主列举了多个例子,如查找最大BST子树、最长连续序列、最深节点路径等,详细解释了如何确定传递的值、如何收集信息以及如何整合这些信息来得出最终结果。这些题目通常涉及递归,复杂度为O(n),并需要考虑空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Tree

传值

这种题型算是树中比较难的类型,因为可能涉及到传递不同的值来决定最终的返回值。首先确定用什么结构,用什么方式传递值是需要仔细考虑的,另外在收集到信息后如何整合贡献到最终结果的过程也可能涉及到复杂的逻辑。所以,对于这个主题,我会尽量把每一个题目列出来分析。


333. Largest BST Subtree
Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest means subtree with largest number of nodes in it.
Note:
A subtree must include all of its descendants.

Example:

Input: [10,5,15,1,8,null,7]

   10 
   / \ 
  5  15 
 / \   \ 
1   8   7

Output: 3
Explanation: The Largest BST Subtree in this case is the highlighted one.
The return value is the subtree’s size, which is 3.
Follow up:
Can you figure out ways to solve it with O(n) time complexity?


题目大意
给一个二叉树,返回子树中最大的二叉搜索树。

解题思路

  1. 传值:
    a. 当前子树的最小值,最大值
    b. 子树包含最大二叉搜索树的大小

  2. 收集:
    从左右子树收集信息,如果左子树最大值小于当前节点,右子树的最小值大于当前节点,那么当前节点更新最大最小值,最大二叉搜索树为1 + 左子树最大搜索树大小 + 右子树最大搜索树大小。否则,只根据较大的那个搜索树更新信息。

复杂度
TC: O(n) SC: O(n)

class Result {  // (size, rangeLower, rangeUpper) -- size of current tree, range of current tree [rangeLower, rangeUpper]
    int size;
    int lower;
    int upper;
    
    Result(int size, int lower, int upper) {
        this.size = size;
        this.lower = lower;
        this.upper = upper;
    }
}

int max = 0;

public int largestBSTSubtree(TreeNode root) {
    if (root == null) { return 0; }    
    traverse(root);
    return max;
}

private Result traverse(TreeNode root) {
    if (root == null) { return new Result(0, Integer.MAX_VALUE, Integer.MIN_VALUE); }
    Result left = traverse(root.left);
    Result right = traverse(root.right);
    if (left.size == -1 || right.size == -1 || root.val <= left.upper || root.val >= right.lower) {
        return new Result(-1, 0, 0);
    }
    int size = left.size + 1 + right.size;
    max = Math.max(size, max);
    return new Result(size, Math.min(left.lower, root.val), Math.max(right.upper, root.val));
}

298. Binary Tree Longest Consecutive Sequence
Given a binary tree, find the length of the longest consecutive sequence path.

The path refers to any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The longest consecutive path need to be from parent to child (cannot be the reverse).

Example 1:

Input:

   1
    \
     3
    / \
   2   4
        \
         5

Output: 3

Explanation: Longest consecutive sequence path is 3-4-5, so return 3.
Example 2:

Input:

   2
    \
     3
    / 
   2    
  / 
 1

Output: 2

Explanation: Longest consecutive sequence path is 2-3, not 3-2-1, so return 2.


题目大意
给一个二叉树,返回之中最长的连续路径的长度(只算由上往下的路径)。

解题思路
这题有两种解法,由顶向下(Top down)和由底向上(Bottom up),这里说下Top down的解法。

  1. 传值:
    a. 当前路径连续路径的长度
    b. 下一个应该碰到的目标节点

  2. 收集:
    如果当前节点等于目标节点,当前连续路径长度加一,更新全局最大连续路径长度。否则,当前连续路径长度为1。

复杂度
TC: O(n) SC: O(n)

//Top Down
int max = 0;
public int longestConsecutive(TreeNode root) {
    if(root == null) return 0;
    helper(root, root.val, 0);
    return max;
}

public void helper(TreeNode node, int target, int curLen){
    if(node == null) return;
    if(node.val == target){
        curLen += 1;
    }else{
        curLen = 1;
    }
    max = Math.max(curLen, max);
    helper(node.left, node.val + 1, curLen);
    helper(node.right, node.val + 1, curLen);
}

//Bottom up
private int maxLength = 0;
public int longestConsecutive(TreeNode root) {
    dfs(root);
    return maxLength;
}

private int dfs(TreeNode p) {
    if (p == null) return 0;
    int L = dfs(p.left) + 1;
    int R = dfs(p.right) + 1;
    if (p.left != null && p.val + 1 != p.left.val) {
        L = 1;
    }
    if (p.right != null && p.val + 1 != p.right.val) {
        R = 1;
    }
    int length = Math.max(L, R);
    maxLength = Math.max(maxLength, length);
    return length;
}

549. Binary Tree Longest Consecutive Sequence II
Given a binary tree, you need to find the length of Longest Consecutive Path in Binary Tree.

Especially, this path can be either increasing or decreasing. For example, [1,2,3,4] and [4,3,2,1] are both considered valid, but the path [1,2,4,3] is not valid. On the other hand, the path can be in the child-Parent-child order, where not necessarily be parent-child order.

Example 1:

Input:
        1
       / \
      2   3

Output: 2
Explanation: The longest consecutive path is [1, 2] or [2, 1].

Example 2:

Input:

        2
       / \
      1   3

Output: 3
Explanation: The longest consecutive path is [1, 2, 3] or [3, 2, 1].
Note: All the values of tree nodes are in the range of [-1e7, 1e7].


题目大意
给一个二叉树,返回之中最长的连续路径的长度。这次连续路径不必要一直由上往下。

解题思路

  1. 传值:
    a. 由此节点开始,单调递增的路径长度。
    b. 由此节点开始,单调递减的路径长度。

  2. 收集:
    如果当前节点的子节点与它的差值绝对值为1,那么检查子节点的连续路径长度,更新当前节点连续路径长度。

复杂度
TC: O(n) SC: O(n)

int maxval = 0;
public int longestConsecutive(TreeNode root) {
    longestPath(root);
    return maxval;
}
public int[] longestPath(TreeNode root) {
    if (root == null)
        return new int[] {0,0};
    int inr = 1, dcr = 1;
    if (root.left != null) {
        int[] l = longestPath(root.left);
        if (root.val == root.left.val + 1)
            dcr = l[1] + 1;
        else if (root.val == root.left.val - 1)
            inr = l[0] + 1;
    }
    if (root.right != null) {
        int[] r = longestPath(root.right);
        if (root.val == root.right.val + 1)
            dcr = Math.max(dcr, r[1] + 1);
        else if (root.val == root.right.val - 1)
            inr = Math.max(inr, r[0] + 1);
    }
    maxval = Math.max(maxval, dcr + inr - 1);
    return new int[] {inr, dcr};
}

863. All Nodes Distance K in Binary Tree
We are given a binary tree (with root node root), a target node, and an integer value K.

Return a list of the values of all nodes that have a distance K from the target node. The answer can be returned in any order.

Example 1:

Input: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2

Output: [7,4,1]

Explanation:
The nodes that are a distance 2 from the target node (with value 5)
have values 7, 4, and 1.

Note that the inputs “root” and “target” are actually TreeNodes.
The descriptions of the inputs above are just serializations of these objects.

Note:

The given tree is non-empty.
Each node in the tree has unique values 0 <= node.val <= 500.
The target node is a node in the tree.
0 <= K <= 1000.


题目大意
给一个二叉树,一个目标节点,一个整数K。返回一个包含所有与目标节点距离为K的节点的列表。

解题思路

  1. 传值:
    a. 由当前节点往下,距离目标节点的距离。
  2. 收集:
    a. 当前节点就是目标节点,由此节点开始往下收集与它距离为K的节点。
    b. 当前节点的左节点与目标节点的距离left不为-1(即目标节点在左子树),如果左节点是目标节点,则从左节点开始往下收集与它距离为K的节点。递归的找与当前节点的右节点距离为K - 2 - left的节点(2代表当前节点与当前节点的左节点)。返回left + 1,表示当前节点与目标节点的距离。

复杂度
TC: O(n) SC: O(n)

List<Integer> ans;
TreeNode target;
int K;
public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
    this.ans = new ArrayList<>();
    this.K = K;
    this.target = target;
    helper(root);
    return ans;
}

public int helper(TreeNode root){
    if (root == null){
        return -1;
    }
    if (root.val == target.val){
        sub(root, K);
        return 0;
    }
    int left = helper(root.left);
    int right = helper(root.right);
    
    if (left != -1){
        if (left == K - 1){
            ans.add(root.val);
        }
        sub(root.right, K - left - 2);
        return left + 1;
    }else if (right != -1){
        if (right == K - 1){
            ans.add(root.val);
        }
        sub(root.left, K - right - 2);
        return right + 1;
    }else{
        return -1;
    }
}

public void sub(TreeNode node, int depth){
    if (node == null || depth < 0) return;
    if (depth == 0){
        ans.add(node.val);
    }else{
        sub(node.left, depth - 1);
        sub(node.right, depth -1);
    }
    
}

337. House Robber III
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the “root.” Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that “all houses in this place forms a binary tree”. It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.

Example 1:

Input: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

Output: 7
Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
Example 2:

Input: [3,4,5,1,3,null,1]

     3
    / \
   4   5
  / \   \ 
 1   3   1

Output: 9
Explanation: Maximum amount of money the thief can rob = 4 + 5 = 9.


题目大意
给一个二叉树,如果取一个节点的值,那么就不能取它左右节点的值。返回取值可能达到的最大总和。

解题思路

  1. 传值:
    a. 如果取当前节点,取值能达到的最大值。
    b.如果不取当前节点,取值能达到的最大值。
  2. 收集:
    a. 如果取当前节点,那么最大值来源于不取左右子节点的最大值 + 当前节点值。
    b.如过不取当前节点,那么最大值来源于左右节点最大值的和。

复杂度
TC: O(n) SC: O(n)

public int rob(TreeNode root) {
    int[] max = robMax(root);
    return Math.max(max[0],max[1]);
}

private int[] robMax(TreeNode root){
    int[] max =new int[2];
    if(root==null)
        return max;
    int[] leftMax = robMax(root.left);
    int[] rightMax = robMax(root.right);
    max[1] = Math.max(leftMax[0],leftMax[1])+Math.max(rightMax[0],rightMax[1]);
    max[0] = root.val+leftMax[1]+rightMax[1];
    return max;
}

250. Count Univalue Subtrees
Given a binary tree, count the number of uni-value subtrees.

A Uni-value subtree means all nodes of the subtree have the same value.

Example :

Input: root = [5,1,5,5,5,null,5]

              5
             / \
            1   5
           / \   \
          5   5   5

Output: 4


题目大意
给一个二叉树,返回包含的节点值都相同的子树的个数。

解题思路

  1. 传值:
    a. 当前子数是否包含的子节点值都相同。
    b.当前节点的值。

  2. 收集:
    a. 如果当前节点的值与左节点的值相同,而且左节点包含的子节点值都相同,那么当前节点可以构成一个有效的单值子树,全局count加1。
    b.如果当前是叶子节点那么也可以构成有效单值子树,count加1。

复杂度
TC: O(n) SC: O(n)

private int count = 0;

public int countUnivalSubtrees(TreeNode root) {  
   unival(root);  
   return count;  
}  
 
private boolean unival(TreeNode root) {  
   if(root == null)  
       return true;  
   if(root.left ==null && root.right == null) {  
       count++;  
       return true;  
   }  
   boolean left = unival(root.left);  
   boolean right = unival(root.right);  
   if(left && right && (root.left == null || root.left.val == root.val) && (root.right == null || root.right.val == root.val)) {  
       count++;  
       return true;  
   }  
   return false;  
}  

相似题目
965. Univalued Binary Tree


508. Most Frequent Subtree Sum
Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a node is defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself). So what is the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency in any order.

Examples 1
Input:

  5
 /  \
2   -3

return [2, -3, 4], since all the values happen only once, return all of them in any order.
Examples 2
Input:

  5
 /  \
2   -5

return [2], since 2 happens twice, however -5 only occur once.
Note: You may assume the sum of values in any subtree is in the range of 32-bit signed integer.


题目大意
给一个二叉树, 定义子树和为根节点的值加上所有子节点的值。找到这个二叉树中出现频率最高的子树和。

解题思路

  1. 传值:
    a. 当前节点的子树和。
    b. 子树和的计数。

  2. 收集:
    a. 当前子树和等于当前节点值加左右节点子树和。
    b.每得到一个新的子树和,更新全局最大频率以及对应的子树和。

复杂度
TC: O(n) SC: O(n)

Map<Integer, Integer> count = new HashMap<Integer, Integer>();
int maxCount = 0;

public int[] findFrequentTreeSum(TreeNode root) {
    dfs(root);
    List<Integer> res = new ArrayList<>();
    for (int s : count.keySet()) {
        if (count.get(s) == maxCount)
            res.add(s);
    }
    return res.stream().mapToInt(i->i).toArray();
}

private int dfs(TreeNode root) {
    if (root == null) return 0;
    int s = dfs(root.left) + dfs(root.right) + root.val;
    count.put(s, count.getOrDefault(s, 0) + 1);
    maxCount = Math.max(maxCount, count.get(s));
    return s;
}

865. Smallest Subtree with all the Deepest Nodes
Given a binary tree rooted at root, the depth of each node is the shortest distance to the root.

A node is deepest if it has the largest depth possible among any node in the entire tree.

The subtree of a node is that node, plus the set of all descendants of that node.

Return the node with the largest depth such that it contains all the deepest nodes in its subtree.

Example 1:

Input: [3,5,1,6,2,0,8,null,null,7,4]
Output: [2,7,4]
Explanation:
在这里插入图片描述

We return the node with value 2, colored in yellow in the diagram.
The nodes colored in blue are the deepest nodes of the tree.
The input “[3, 5, 1, 6, 2, 0, 8, null, null, 7, 4]” is a serialization of the given tree.
The output “[2, 7, 4]” is a serialization of the subtree rooted at the node with value 2.
Both the input and output have TreeNode type.

Note:

The number of nodes in the tree will be between 1 and 500.
The values of each node are unique.


题目大意
给一个二叉树,返回所有最深节点的根节点。

解题思路

  1. 传值:
    a. 当前节点深度。
    b.当前子树中最深节点的父节点。

  2. 收集:
    a. 如果当前节点的左右子树返回的深度相同,那么返回(当前节点,左子树深度 + 1)。
    b. 如果左子树深度较大,则返回(左子树最深节点的根节点,左子树的深度 + 1)。

复杂度
TC: O(n) SC:O(n)

class Result {
    TreeNode node;
    int dist;
    Result(TreeNode n, int d) {
        node = n;
        dist = d;
    }
}

public TreeNode subtreeWithAllDeepest(TreeNode root) {
    return dfs(root).node;
}

// Return the result of the subtree at this node.
public Result dfs(TreeNode node) {
    if (node == null) return new Result(null, 0);
    Result L = dfs(node.left),
           R = dfs(node.right);
    if (L.dist > R.dist) return new Result(L.node, L.dist + 1);
    if (L.dist < R.dist) return new Result(R.node, R.dist + 1);
    return new Result(node, L.dist + 1);
}

979. Distribute Coins in Binary Tree
Given the root of a binary tree with N nodes, each node in the tree has node.val coins, and there are N coins total.

In one move, we may choose two adjacent nodes and move one coin from one node to another. (The move may be from parent to child, or from child to parent.)

Return the number of moves required to make every node have exactly one coin.

Example 1:
在这里插入图片描述

Input: [3,0,0]
Output: 2
Explanation: From the root of the tree, we move one coin to its left child, and one coin to its right child.
Example 2:
在这里插入图片描述

Input: [0,3,0]
Output: 3
Explanation: From the left child of the root, we move two coins to the root [taking two moves]. Then, we move one coin from the root of the tree to the right child.
Example 3:

Input: [1,0,2]
Output: 2
Example 4:

在这里插入图片描述

Input: [1,0,0,null,3]
Output: 4

Note:

1<= N <= 100
0 <= node.val <= N


题目大意
给一个二叉树,节点的值代表这个节点有多少个硬币。求要用多少步才能让树种每个节点的硬币数一样。

解题思路

  1. 传值:
    a. 当前节点的值。
    b.当前节点需要给出硬币的值(可以为负)。

  2. 收集:
    a. 满足当前子树硬币值平均所需要的步数等于左节点需要给出银币数的绝对值 + 右节点需要给出银币数的绝对值。
    b. 当前节点需要给出的硬币数为左子树需要给出的硬币数 + 左子树需要给出的硬币数 + 当前节点的值 - 1, 1代表当前节点需要至少留一个硬币。

复杂度
TC: O(n) SC: O(n)

int ans;
public int distributeCoins(TreeNode root) {
    ans = 0;
    helper(root);
    return ans;
}

public int helper(TreeNode root){
    if (root == null){
        return 0;
    }
    int left = helper(root.left);
    int right = helper(root.right);
    
    ans += Math.abs(left) + Math.abs(right);
    return root.val + left + right - 1;
}

687. Longest Univalue Path
Given a binary tree, find the length of the longest path where each node in the path has the same value. This path may or may not pass through the root.

The length of path between two nodes is represented by the number of edges between them.

Example 1:

Input:

              5
             / \
            4   5
           / \   \
          1   1   5

Output: 2

Example 2:

Input:

              1
             / \
            4   5
           / \   \
          4   4   5

Output: 2
Note: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000.


题目大意
给一个二叉树,找其中节点值都相同的最大路径,路径用边的数量表示,可以通过根节点。

解题思路

  1. 传值:
    a. 当前节点子树中节点值都相同的最大路径。
    b. 当前节点的值。

  2. 收集:
    a. 和根节点值相同的左子树节点值都相同最大路径的长度。右子树同理。
    b. 根据左右子树路径长度更新当前全局最大路径长度。
    c. 返回较大的子树的最大路径长度。

复杂度
TC: O(n) SC: O(n)

int length;
public int longestUnivaluePath(TreeNode root) {
    return Math.max(longestUnivaluePathHelper(root,0),length);
}

private int longestUnivaluePathHelper(TreeNode root,int prev){
    if(root==null)
        return 0;
    
    int left = longestUnivaluePathHelper(root.left,root.val);
    int right = longestUnivaluePathHelper(root.right,root.val);
    
    length = Math.max(length,left+right);
    
    if(root.val == prev)
        return Math.max(left,right)+1;
    else return 0;
}

相似题目
543. Diameter of Binary Tree


653. Two Sum IV - Input is a BST
Given a Binary Search Tree and a target number, return true if there exist two elements in the BST such that their sum is equal to the given target.

Example 1:

Input:

    5
   / \
  3   6
 / \   \
2   4   7

Target = 9

Output: True

Example 2:

Input:

    5
   / \
  3   6
 / \   \
2   4   7

Target = 28

Output: False


题目大意
给一个二叉搜索树,一个目标整数。找这个树中是否存在两个节点的值的和是目标整数。

解题思路

  1. 传值:
    a. 当前节点的值。
    b. 目标整数。
  2. 收集:
    a. 如果当前节点值等于目标值,且不等于另一个要找的节点,就返回true。
    b. 如果当前的值不等于目标值,比较目标值与当前节点值,按照二叉树性质分别在合适的子树中找。

复杂度
TC: O(n) SC: O(n)

public boolean findTarget(TreeNode root, int k) {
    return dfs(root, root,  k);
}

public boolean dfs(TreeNode root,  TreeNode cur, int k){
    if(cur == null)return false;
    return search(root, cur, k - cur.val) || dfs(root, cur.left, k) || dfs(root, cur.right, k);
}

public boolean search(TreeNode root, TreeNode cur, int value){
    if(root == null)return false;
    return (root.val == value) && (root != cur) 
        || (root.val < value) && search(root.right, cur, value) 
            || (root.val > value) && search(root.left, cur, value);
}

530. Minimum Absolute Difference in BST
Given a binary search tree with non-negative values, find the minimum absolute difference between values of any two nodes.

Example:

Input:

   1
    \
     3
    /
   2

Output:
1

Explanation:
The minimum absolute difference is 1, which is the difference between 2 and 1 (or between 2 and 3).

Note: There are at least two nodes in this BST.


题目大意
给一个二叉搜索树,找出节点中绝对差值最小的值。

解题思路
1.传值:
a. 当前节点值。
b. 中序遍历情况下,当前节点的前节点值。

  1. 收集:
    计算当前节点与它的先节点的差值,更新全局最小差值。

复杂度
TC: O(n) SC: O(n)

//Binary Search Tree
int min = Integer.MAX_VALUE;
TreeNode pre;
public int getMinimumDifference(TreeNode root) {
	findMin(root);
	return min;
}

private void findMin(TreeNode root) {
	if(root == null) return;
    getMinimumDifference(root.left);
    if(pre != null)  min = Math.min(min, Math.abs(root.val - pre.val));
    pre = root;
    getMinimumDifference(root.right);
    
}

//Regular Binary Tree
//TC: O(nlgn)  SC: O(n)
TreeSet<Integer> set = new TreeSet<>();
int min = Integer.MAX_VALUE;

public int getMinimumDifference(TreeNode root) {
    if (root == null) return min;
    
    if (!set.isEmpty()) {
        if (set.floor(root.val) != null) {
            min = Math.min(min, root.val - set.floor(root.val));
        }
        if (set.ceiling(root.val) != null) {
            min = Math.min(min, set.ceiling(root.val) - root.val);
        }
    }
    
    set.add(root.val);
    
    getMinimumDifference(root.left);
    getMinimumDifference(root.right);
    
    return min;
}

501. Find Mode in Binary Search Tree
Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequently occurred element) in the given BST.

Assume a BST is defined as follows:

The left subtree of a node contains only nodes with keys less than or equal to the node’s key.
The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
Both the left and right subtrees must also be binary search trees.

For example:
Given BST [1,null,2,2],

   1
    \
     2
    /
   2

return [2].

Note: If a tree has more than one mode, you can return them in any order.

Follow up: Could you do that without using any extra space? (Assume that the implicit stack space incurred due to recursion does not count).


题目大意
给一个二叉搜索树,找出节点中的众数。

解题思路

  1. 传值:
    a. 当前节点的频率。
    b. 当前最大的频率。
    c. 中序遍历的前导节点。

  2. 收集:
    a. 利用二叉搜索树的中序遍历的特性,如果当前节点的值与前导节点相同,那么就把当前节点的频率加1.
    b. 如果当前节点的频率大于全局最大频率,则更新最大频率。
    c.如果当前节点的频率等于全局最大频率,则把当前节点加入需要返回的列表中。

复杂度
TC: O(n) SC: O(n)

int max = 0;
int counter = 1;
TreeNode prev = null;

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


public void inOrder(TreeNode root, List<Integer> result){
    
    if(root == null)
        return;
    
    inOrder(root.left, result);
    
    if(prev != null){
        if(prev.val == root.val)
            counter++;
        else{
            counter = 1;
        }
    }
     
    prev = root;
    
    if(counter > max){
        result.clear();
        result.add(root.val);
        max = counter;
        
    }else if(counter == max){
        result.add(root.val);
    }
    
    inOrder(root.right, result);        
}

671. Second Minimum Node In a Binary Tree
Given a non-empty special binary tree consisting of nodes with the non-negative value, where each node in this tree has exactly two or zero sub-node. If the node has two sub-nodes, then this node’s value is the smaller value among its two sub-nodes. More formally, the property root.val = min(root.left.val, root.right.val) always holds.

Given such a binary tree, you need to output the second minimum value in the set made of all the nodes’ value in the whole tree.

If no such second minimum value exists, output -1 instead.

Example 1:

Input: 
    2
   / \
  2   5
     / \
    5   7

Output: 5
Explanation: The smallest value is 2, the second smallest value is 5.

Example 2:

Input:

    2
   / \
  2   2

Output: -1
Explanation: The smallest value is 2, but there isn’t any second smallest value.


题目大意
给一个二叉树,节点满足root.val = min(root.left.val, root.right.val),求这棵树中第二小的节点。

解题思路

  1. 传值:
    a. 当前节点值。
    b. 当前第二小的值ans。
    c. 当前最小值。

  2. 收集:
    a. 如果当前最小值<根节点值< 当前第二小的值,那么更新第二小的值为当前根节点。
    b. 如果当前节点值等于最小值,递归的在左右子树中找第二最小值。

复杂度
TC: O(n) SC: O(n)

int min1;
long ans = Long.MAX_VALUE;

public void dfs(TreeNode root) {
    if (root != null) {
        if (min1 < root.val && root.val < ans) {
            ans = root.val;
        } else if (min1 == root.val) {
            dfs(root.left);
            dfs(root.right);
        }
    }
}
public int findSecondMinimumValue(TreeNode root) {
    min1 = root.val;
    dfs(root);
    return ans < Long.MAX_VALUE ? (int) ans : -1;
}

255. Verify Preorder Sequence in Binary Search Tree
Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary search tree.

You may assume each number in the sequence is unique.

Consider the following binary search tree:

     5
    / \
   2   6
  / \
 1   3

Example 1:

Input: [5,2,6,1,3]
Output: false
Example 2:

Input: [5,2,1,3,6]
Output: true
Follow up:
Could you do it using only constant space complexity?


题目大意
给一个数组,证明他是否是按照一个二叉搜索树的先序遍历排序的。

解题思路

  1. 传值:
    a. 当前遍历的全局最大值,最小值。
    b. 当前遍历的index。

  2. 收集:
    a. 如果当前节点小于全局最小值,或者大于全局最大值则停止检查。
    b.如果最终能成功的遍历完数组所有的值,那么就是合法的先序遍历。

复杂度
TC: O(n) SC: O(n)

int idx = 0;

public boolean verifyPreorder(int[] preorder) {
    traverse(preorder, Integer.MIN_VALUE, Integer.MAX_VALUE);
    return idx==preorder.length;
}
void traverse(int[] preorder, int min, int max) {
    if(idx == preorder.length) return;
    int v = preorder[idx];

    if(v > max || v < min) //no such tree don't advance idx
        return;
    idx ++;
    traverse(preorder, min, v);//try left
    traverse(preorder, v, max);//try right
}

623. Add One Row to Tree
Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value v at the given depth d. The root node is at depth 1.

The adding rule is: given a positive integer depth d, for each NOT null tree nodes N in depth d-1, create two tree nodes with value v as N’s left subtree root and right subtree root. And N’s original left subtree should be the left subtree of the new left subtree root, its original right subtree should be the right subtree of the new right subtree root. If depth d is 1 that means there is no depth d-1 at all, then create a tree node with value v as the new root of the whole original tree, and the original tree is the new root’s left subtree.

Example 1:
Input:
A binary tree as following:

       4
     /   \
    2     6
   / \   / 
  3   1 5   

v = 1

d = 2

Output:

       4
      / \
     1   1
    /     \
   2       6
  / \     / 
 3   1   5   

Example 2:
Input:
A binary tree as following:

      4
     /   
    2    
   / \   
  3   1    

v = 1

d = 3

Output:

      4
     /   
    2
   / \    
  1   1
 /     \  
3       1

Note:
The given d is in range [1, maximum depth of the given tree + 1].
The given binary tree has at least one tree node.


题目大意
给一个二叉树,两个整数v, d。 要求在深度为d的地方插入一行值为v的节点。

解题思路

  1. 传值:
    a. 当前节点的深度
    b. 需要插入节点的深度。
    c. 当前节点的值。

  2. 收集:
    a. 如果当前节点的深度为d - 1,那么在这个节点与它的左右节点之间加入值为v的节点。
    b. 如果当前节点深度不足d - 1, 那么继续遍历左右子树。

复杂度
TC: O(n) SC: O(n)

//Recursion
public TreeNode addOneRow(TreeNode t, int v, int d) {
    if (d == 1) {
        TreeNode n = new TreeNode(v);
        n.left = t;
        return n;
    }
    insert(v, t, 1, d);
    return t;
}

public void insert(int val, TreeNode node, int depth, int n) {
    if (node == null)
        return;
    if (depth == n - 1) {
        TreeNode t = node.left;
        node.left = new TreeNode(val);
        node.left.left = t;
        t = node.right;
        node.right = new TreeNode(val);
        node.right.right = t;
    } else {
        insert(val, node.left, depth + 1, n);
        insert(val, node.right, depth + 1, n);
    }
}

//DFS
class Node{
    Node(TreeNode n,int d){
        node=n;
        depth=d;
    }
    TreeNode node;
    int depth;
}
public TreeNode addOneRow(TreeNode t, int v, int d) {
    if (d == 1) {
        TreeNode n = new TreeNode(v);
        n.left = t;
        return n;
    } 
    Stack<Node> stack=new Stack<>();
    stack.push(new Node(t,1));
    while(!stack.isEmpty())
    {
        Node n=stack.pop();
        if(n.node==null)
            continue;
        if (n.depth == d - 1 ) {
            TreeNode temp = n.node.left;
            n.node.left = new TreeNode(v);
            n.node.left.left = temp;
            temp = n.node.right;
            n.node.right = new TreeNode(v);
            n.node.right.right = temp;
            
        } else{
            stack.push(new Node(n.node.left, n.depth + 1));
            stack.push(new Node(n.node.right, n.depth + 1));
        }
    }
    return t;
}

//BFS
public TreeNode addOneRow(TreeNode t, int v, int d) {
    if (d == 1) {
        TreeNode n = new TreeNode(v);
        n.left = t;
        return n;
    }
    Queue < TreeNode > queue = new LinkedList < > ();
    queue.add(t);
    int depth = 1;
    while (depth < d - 1) {
        Queue < TreeNode > temp = new LinkedList < > ();
        while (!queue.isEmpty()) {
            TreeNode node = queue.remove();
            if (node.left != null) temp.add(node.left);
            if (node.right != null) temp.add(node.right);
        }
        queue = temp;
        depth++;
    }
    while (!queue.isEmpty()) {
        TreeNode node = queue.remove();
        TreeNode temp = node.left;
        node.left = new TreeNode(v);
        node.left.left = temp;
        temp = node.right;
        node.right = new TreeNode(v);
        node.right.right = temp;
    }
    return t;
}

99. Recover Binary Search Tree
Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Example 1:

Input: [1,3,null,null,2]

   1
  /
 3
  \
   2

Output: [3,1,null,null,2]

   3
  /
 1
  \
   2

Example 2:

Input: [3,1,4,null,null,2]

  3
 / \
1   4
   /
  2

Output: [2,1,4,null,null,3]

  2
 / \
1   4
   /
  3

Follow up:

A solution using O(n) space is pretty straight forward.
Could you devise a constant space solution?


题目大意
已知在二叉搜索树中有两个值被翻转了,要求回复这个二叉搜索树。

解题大意

  1. 传值:
    a. 当前节点的值。
    b. 中序遍历先导节点的值。
    c. 当前第一个不合法的节点。
    d. 当前第二个不合法的节点。

  2. 收集:
    a. 如果中序遍历先导节点大于当前节点,说明先导节点违反和二叉树规则,如果当前第一个不合法的节点为null,则更新它为这个先导节点。
    b. 如果当前第一个不合法的节点不为null,更新第二个不合法节点为先导节点。

复杂度
TC: O(n) SC: O(n)

private TreeNode prev;
private TreeNode firstNode;
private TreeNode lastNode;
public void recoverTree(TreeNode root) {
    inOrder(root);
    int temp = firstNode.val;
    firstNode.val = lastNode.val;
    lastNode.val = temp;
}

private void inOrder(TreeNode node) {
    if (node == null) {
        return;
    }
    inOrder(node.left);
    if (prev != null && prev.val > node.val) {
        if (firstNode == null) {
            firstNode = prev;
        }
        lastNode = node;
    }
    prev = node;
    inOrder(node.right);
}

285. Inorder Successor in BST
Given a binary search tree and a node in it, find the in-order successor of that node in the BST.

The successor of a node p is the node with the smallest key greater than p.val.

Example 1:
在这里插入图片描述

Input: root = [2,1,3], p = 1
Output: 2
Explanation: 1’s in-order successor node is 2. Note that both p and the return value is of TreeNode type.
Example 2:
在这里插入图片描述

Input: root = [5,3,6,2,4,null,null,1], p = 6
Output: null
Explanation: There is no in-order successor of the current node, so the answer is null.

Note:

If the given node has no in-order successor in the tree, return null.
It’s guaranteed that the values of the tree are unique.


题目大意
给一个二叉搜索树和其中的一个节点,找出他的中序先导节点。

解题思路

  1. 传值:
    a. 当前节点的值。
    b. 当前节点的先导节点。

  2. 收集:
    a. 如果当前节点的值小于目标节点,查当前节点的右节点。
    b. 如果当前节点的值大于目标节点,更新先导节点,查当前节点的左节点。

复杂度
TC: O(lgn) SC: O(n)

public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
    if (root == null || p == null) return null;
    
    TreeNode q = null;
    
    while(root != null){
        if(p.val < root.val){
            q = root;
            root = root.left;
        }else{
            root = root.right;
        }
    }
    return q;
}

272. Closest Binary Search Tree Value II
Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.

Note:

Given target value is a floating point.
You may assume k is always valid, that is: k ≤ total nodes.
You are guaranteed to have only one unique set of k values in the BST that are closest to the target.
Example:

Input: root = [4,2,5,1,3], target = 3.714286, and k = 2

    4
   / \
  2   5
 / \
1   3

Output: [4,3]
Follow up:
Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)?


题目大意
给一个二叉搜索树,一个整数target。返回k个跟target最近的节点。

解题思路
如果用两个栈的解法可以把复杂度提高到O(lgn)。 首先得到比targe小的k个节点,然后得到比target大的k个节点,在这些节点中选择与target最近的节点,具体解法类似于合并两个排序列表。

递归:

  1. 传值:
    a. 当前节点值。
    b. 目标节点值。
    c. 当前与目标节点最近的k个节点的列表。

  2. 收集:
    a. 如果当前节点与目标节点差值的绝对值大于列表的第一个元素,那么返回。
    b. 如果当前节点与目标节点差值的绝对值小于列表的第一个元素,那么弹出第一个元素,把当前元素加入列表。

复杂度
4. TC: O(n) SC: O(n)
5. TC: O(lgn) SC: O(lgn)

//1. TC: O(n) O(n)
public List<Integer> closestKValues(TreeNode root, double target, int k) {
    LinkedList<Integer> result = new LinkedList<>();
    inorder(root, target, k, result);
    return result;
}

private void inorder(TreeNode root, double target, int k, LinkedList<Integer> result) {
    if (root == null) return;
    inorder(root.left, target, k, result);
    if(result.size() == k) {
        if(Math.abs(target - result.getFirst()) < Math.abs(target - root.val)) {              
            return;
        } else {
            result.removeFirst();
        }
    }
    result.addLast(root.val);
    inorder(root.right, target, k, result);
}

//2. TC: O(lgn) SC: O(n)
public List<Integer> closestKValues(TreeNode root, double target, int k) {
  List<Integer> res = new ArrayList<>();

  Stack<Integer> s1 = new Stack<>(); // predecessors
  Stack<Integer> s2 = new Stack<>(); // successors

  inorder(root, target, false, s1);
  inorder(root, target, true, s2);

  while (k-- > 0) {
    if (s1.isEmpty())
      res.add(s2.pop());
    else if (s2.isEmpty())
      res.add(s1.pop());
    else if (Math.abs(s1.peek() - target) < Math.abs(s2.peek() - target))
      res.add(s1.pop());
    else
      res.add(s2.pop());
  }

  return res;
}

// inorder traversal
void inorder(TreeNode root, double target, boolean reverse, Stack<Integer> stack) {
  if (root == null) return;

  inorder(reverse ? root.right : root.left, target, reverse, stack);
  // early terminate, no need to traverse the whole tree
  if ((reverse && root.val <= target) || (!reverse && root.val > target)) return;
  // track the value of current node
  stack.push(root.val);
  inorder(reverse ? root.left : root.right, target, reverse, stack);
}

相似题目
270. Closest Binary Search Tree Value


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值