A maximum tree is a tree where every node has a value greater than any other value in its subtree.
You are given the root
of a maximum binary tree and an integer val
.
Just as in the previous problem, the given tree was constructed from a list a
(root = Construct(a)
) recursively with the following Construct(a)
routine:
a
is empty, return null
.a[i]
be the largest element of a
. Create a root
node with the value a[i]
.root
will be Construct([a[0], a[1], ..., a[i - 1]])
.root
will be Construct([a[i + 1], a[i + 2], ..., a[a.length - 1]])
.root
.Note that we were not given a
directly, only a root node root = Construct(a)
.
Suppose b
is a copy of a
with the value val
appended to it. It is guaranteed that b
has unique values.
Return Construct(b)
.
Example 1:
Input: root = [4,1,3,null,null,2], val = 5 Output: [5,4,null,1,3,null,null,2] Explanation: a = [1,4,2,3], b = [1,4,2,3,5]
Example 2:
Input: root = [5,2,4,null,1], val = 3 Output: [5,2,4,null,1,null,3] Explanation: a = [2,1,5,4], b = [2,1,5,4,3]
Example 3:
Input: root = [5,2,3,null,1], val = 4 Output: [5,2,4,null,1,3] Explanation: a = [2,1,5,3], b = [2,1,5,3,4]
Constraints:
[1, 100]
.1 <= Node.val <= 100
1 <= val <= 100
This problem asks to insert a new node with value val
into a maximum binary tree. A maximum binary tree is a tree where every node's value is greater than any node in its subtree. The insertion should maintain this maximum tree property.
This approach leverages the recursive nature of constructing a maximum binary tree. We recursively traverse the tree, looking for the appropriate place to insert the new node.
Algorithm:
null
or its value is less than val
, create a new node with val
and make the current node its left child. This new node becomes the new root of the subtree.val
. This ensures that val
is inserted into the correct position within the right subtree, maintaining the maximum tree property.Time Complexity: O(N), where N is the number of nodes in the tree. This is because in the worst case we traverse the entire tree. Space Complexity: O(N) in the worst case due to the recursive call stack. The recursion depth can be at most N if the tree is skewed.
This approach avoids recursion by iteratively traversing the tree to find the correct insertion point.
Algorithm:
val
, create a new node with val
and make the root its left child. This is the new root.val
, continue traversing to the right.val
, create a new node with val
, make the current node's right child the left child of the new node, and then set the new node as the current node's right child.Time Complexity: O(N), where N is the number of nodes in the tree. In the worst case, we might traverse the entire right branch. Space Complexity: O(1). We are using only a constant number of extra variables.
Approach 1 (Recursive):
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def insertIntoMaxTree(self, root: TreeNode, val: int) -> TreeNode:
if not root or root.val < val:
return TreeNode(val, root)
root.right = self.insertIntoMaxTree(root.right, val)
return root
Approach 2 (Iterative):
class Solution:
def insertIntoMaxTree(self, root: TreeNode, val: int) -> TreeNode:
if not root or root.val < val:
return TreeNode(val, root)
curr = root
node = TreeNode(val)
while curr.right and curr.right.val > val:
curr = curr.right
node.left = curr.right
curr.right = node
return root
The code examples in other languages (Java, C++, Go, TypeScript, Rust, C) follow similar logic, reflecting the algorithms described above. The choice between the recursive and iterative approach is often a matter of preference and potential considerations about stack overflow in very deep trees (favoring iterative in those scenarios). Both have the same asymptotic time complexity.