题目
标题和出处
标题:最大二叉树 II
难度
5 级
题目描述
要求
如果一个树满足其中每个结点的值都大于其子树中的任何其他值,则这样的树为最大树。
给定最大树的根结点 root \texttt{root} root 和一个整数 val \texttt{val} val。
就像之前的问题那样,给定的树是从列表 a \texttt{a} a( root = Construct(a) \texttt{root = Construct(a)} root = Construct(a))递归地使用下述 Construct(a) \texttt{Construct(a)} Construct(a) 过程构造的:
- 如果 a \texttt{a} a 为空,返回 null \texttt{null} null。
- 否则,令 a[i] \texttt{a[i]} a[i] 为 a \texttt{a} a 的最大元素。创建值为 a[i] \texttt{a[i]} a[i] 的根结点 root \texttt{root} root
- root \texttt{root} root 的左子树将被构建为 Construct([a[0], a[1], ..., a[i - 1]]) \texttt{Construct([a[0], a[1], ..., a[i - 1]])} Construct([a[0], a[1], ..., a[i - 1]])。
- root \texttt{root} root 的右子树将被构建为 Construct([a[i + 1], a[i + 2], ..., a[a.length - 1]]) \texttt{Construct([a[i + 1], a[i + 2], ..., a[a.length - 1]])} Construct([a[i + 1], a[i + 2], ..., a[a.length - 1]])。
- 返回 root \texttt{root} root。
请注意,我们没有直接给定 a \texttt{a} a,只有一个根结点 root = Construct(a) \texttt{root = Construct(a)} root = Construct(a)。
假设 b \texttt{b} b 是将 a \texttt{a} a 复制后在末尾添加值 val \texttt{val} val 之后的列表。题目数据保证 b \texttt{b} b 中的值各不相同。
返回 Construct(b) \texttt{Construct(b)} Construct(b)。
示例
示例 1:
输入: root = [4,1,3,null,null,2], val = 5 \texttt{root = [4,1,3,null,null,2], val = 5} root = [4,1,3,null,null,2], val = 5
输出: [5,4,null,1,3,null,null,2] \texttt{[5,4,null,1,3,null,null,2]} [5,4,null,1,3,null,null,2]
解释: a = [1,4,2,3], b = [1,4,2,3,5] \texttt{a = [1,4,2,3], b = [1,4,2,3,5]} a = [1,4,2,3], b = [1,4,2,3,5]
示例 2:
输入: root = [5,2,4,null,1], val = 3 \texttt{root = [5,2,4,null,1], val = 3} root = [5,2,4,null,1], val = 3
输出: [5,2,4,null,1,null,3] \texttt{[5,2,4,null,1,null,3]} [5,2,4,null,1,null,3]
解释: a = [2,1,5,4], b = [2,1,5,4,3] \texttt{a = [2,1,5,4], b = [2,1,5,4,3]} a = [2,1,5,4], b = [2,1,5,4,3]
示例 3:
输入: root = [5,2,3,null,1], val = 4 \texttt{root = [5,2,3,null,1], val = 4} root = [5,2,3,null,1], val = 4
输出: [5,2,4,null,1,3] \texttt{[5,2,4,null,1,3]} [5,2,4,null,1,3]
解释: a = [2,1,5,3], b = [2,1,5,3,4] \texttt{a = [2,1,5,3], b = [2,1,5,3,4]} a = [2,1,5,3], b = [2,1,5,3,4]
数据范围
- 树中结点数目在范围 [1, 100] \texttt{[1, 100]} [1, 100] 内
- 1 ≤ Node.val ≤ 100 \texttt{1} \le \texttt{Node.val} \le \texttt{100} 1≤Node.val≤100
- 树中的所有值各不相同
- 1 ≤ val ≤ 100 \texttt{1} \le \texttt{val} \le \texttt{100} 1≤val≤100
解法一
思路和算法
由于整数 val \textit{val} val 位于列表的末尾,因此和原最大二叉树相比,新最大二叉树多了一个结点 val \textit{val} val 且结点 val \textit{val} val 在最右侧,其余结点的左右相对位置不变。问题转换成在原最大二叉树中插入结点 val \textit{val} val 并保持最大二叉树的性质,然后返回新最大二叉树。
如果原最大二叉树为空,则新最大二叉树只有一个结点 val \textit{val} val。如果整数 val \textit{val} val 大于原最大二叉树的根结点值,则由于最大二叉树的根结点值大于任何其他结点值,因此整数 val \textit{val} val 大于原最大二叉树的任何结点值,将结点 val \textit{val} val 作为新最大二叉树的根结点,将原最大二叉树作为结点 val \textit{val} val 的左子树,即可得到新最大二叉树。
如果整数 val \textit{val} val 小于原最大二叉树的根结点值,则需要在原最大二叉树的右子树中插入结点 val \textit{val} val,在右子树中使用同样的方法寻找插入结点的位置。因此插入结点的过程是一个递归的过程,递归的终止条件是原最大二叉树为空或者待插入结点值大于原最大二叉树的根结点值,对于其余情况,则在原最大二叉树的右子树中递归地寻找插入结点的位置并完成插入操作。
代码
class Solution {
public TreeNode insertIntoMaxTree(TreeNode root, int val) {
TreeNode node = new TreeNode(val);
if (root == null) {
return node;
}
if (val > root.val) {
node.left = root;
return node;
}
root.right = insertIntoMaxTree(root.right, val);
return root;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。寻找插入结点的位置最多需要遍历二叉树的每一层各一次,因此时间复杂度取决于二叉树的高度,最坏情况下二叉树的高度是 O ( n ) O(n) O(n)。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是递归调用的栈空间,取决于二叉树的高度,最坏情况下二叉树的高度是 O ( n ) O(n) O(n)。
解法二
思路和算法
递归实现也可以改成迭代实现。由于给定的最大二叉树一定不为空,因此可以直接比较给定的整数 val \textit{val} val 和最大二叉树的根结点值的大小。如果整数 val \textit{val} val 大于原最大二叉树的根结点值,则将结点 val \textit{val} val 作为新最大二叉树的根结点,将原最大二叉树作为结点 val \textit{val} val 的左子树,即可得到新最大二叉树。
如果整数 val \textit{val} val 小于原最大二叉树的根结点值,则需要在原最大二叉树的右子树中插入结点 val \textit{val} val,需要首先找到插入结点 val \textit{val} val 的位置,然后插入结点 val \textit{val} val。寻找插入结点 val \textit{val} val 的位置时,需要在遍历过程中记录上一个结点 prev \textit{prev} prev 和当前结点 curr \textit{curr} curr,找到插入结点 val \textit{val} val 的位置之后,利用 prev \textit{prev} prev 和 curr \textit{curr} curr 完成插入操作。具体操作如下。
-
如果 curr \textit{curr} curr 不为空且整数 val \textit{val} val 小于 curr \textit{curr} curr 的结点值,则插入结点 val \textit{val} val 的位置在 curr \textit{curr} curr 的右子树中,因此将 curr \textit{curr} curr 赋给 prev \textit{prev} prev,将 curr \textit{curr} curr 移动到右子结点。重复该操作直到 curr \textit{curr} curr 为空或者整数 val \textit{val} val 大于 curr \textit{curr} curr 的结点值,此时找到插入结点 val \textit{val} val 的位置。
-
找到插入结点 val \textit{val} val 的位置之后,整数 val \textit{val} val 一定小于 prev \textit{prev} prev 的结点值,且当 curr \textit{curr} curr 不为空时,整数 val \textit{val} val 一定大于 curr \textit{curr} curr 的结点值,因此将 prev \textit{prev} prev 的右子结点设为结点 val \textit{val} val,将结点 val \textit{val} val 的左子结点设为 curr \textit{curr} curr(当 curr \textit{curr} curr 为空时该操作同样适用)。
由于当整数 val \textit{val} val 小于原最大二叉树的根结点值时,插入结点的位置一定不是根结点,因此插入操作不会改变最大二叉树的根结点,原最大二叉树的根结点也是新最大二叉树的根结点。
使用迭代实现可以省略递归调用的栈空间,将空间复杂度降低到 O ( 1 ) O(1) O(1)。
代码
class Solution {
public TreeNode insertIntoMaxTree(TreeNode root, int val) {
TreeNode node = new TreeNode(val);
if (val > root.val) {
node.left = root;
return node;
}
TreeNode prev = null, curr = root;
while (curr != null && val < curr.val) {
prev = curr;
curr = curr.right;
}
prev.right = node;
node.left = curr;
return root;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。寻找插入结点的位置最多需要遍历二叉树的每一层各一次,因此时间复杂度取决于二叉树的高度,最坏情况下二叉树的高度是 O ( n ) O(n) O(n)。
-
空间复杂度: O ( 1 ) O(1) O(1)。