You are given an integer array nums
with no duplicates. A maximum binary tree can be built recursively from nums
using the following algorithm:
nums
.Return the maximum binary tree built from nums
.
Example 1:
Input: nums = [3,2,1,6,0,5] Output: [6,3,5,null,2,0,null,null,1] Explanation: The recursive calls are as follow: - The largest value in [3,2,1,6,0,5] is 6. Left prefix is [3,2,1] and right suffix is [0,5]. - The largest value in [3,2,1] is 3. Left prefix is [] and right suffix is [2,1]. - Empty array, so no child. - The largest value in [2,1] is 2. Left prefix is [] and right suffix is [1]. - Empty array, so no child. - Only one element, so child is a node with value 1. - The largest value in [0,5] is 5. Left prefix is [0] and right suffix is []. - Only one element, so child is a node with value 0. - Empty array, so no child.
Example 2:
Input: nums = [3,2,1] Output: [3,null,2,null,1]
Constraints:
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums
are unique.This problem asks to construct a maximum binary tree from an integer array. A maximum binary tree is defined recursively:
We'll explore three approaches to solve this problem: a recursive approach, a segment tree approach, and an iterative approach using a stack.
This is the most straightforward approach, directly mirroring the recursive definition of the maximum binary tree.
Algorithm:
nums
and its index.Time Complexity: O(N^2), where N is the length of the input array. Finding the maximum in each recursive call takes O(N) time in the worst case. The recursion depth is at most N.
Space Complexity: O(N) in the worst case due to the recursion stack and the implicit space used by the tree.
Code (Python):
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
def dfs(nums):
if not nums:
return None
max_val = max(nums)
max_index = nums.index(max_val)
root = TreeNode(max_val)
root.left = dfs(nums[:max_index])
root.right = dfs(nums[max_index+1:])
return root
return dfs(nums)
The code in other languages (Java, C++, Go, TypeScript, Rust, C) follows a similar structure, differing only in syntax and data structure implementations.
This approach uses a segment tree to efficiently find the maximum value in any subarray.
Algorithm:
Time Complexity: O(N log N) for building the segment tree, and O(N log N) for constructing the binary tree. The overall time complexity is O(N log N).
Space Complexity: O(N) for the segment tree and O(N) for the recursion stack and the tree itself.
Code (Python):
(The Python code for the Segment Tree solution is provided in the original response.) Similar implementations exist for other languages. Note that this is a significantly more complex solution than the recursive approach and adds considerable overhead. Unless extremely large input arrays are expected, the recursive approach is simpler and arguably faster.
This approach uses a stack to construct the tree iteratively.
Algorithm:
v
:
v
.v
, pop the top element. The popped elements become the left children of the current node.Time Complexity: O(N), as we iterate through the array once.
Space Complexity: O(N) in the worst case, as the stack may contain up to N nodes.
Code (Python):
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
stack = []
for num in nums:
node = TreeNode(num)
while stack and stack[-1].val < num:
node.left = stack.pop()
if stack:
stack[-1].right = node
stack.append(node)
return stack[0]
Again, the implementation in other languages is very similar.
In Summary:
The recursive solution (Solution 1) is the simplest and easiest to understand. Solution 3 offers a significant improvement in time complexity, making it the most efficient approach for large datasets. Solution 2 is considerably more complex and doesn't offer a significant performance advantage unless dealing with extremely large inputs. Choose the solution that best fits your needs and understanding.