给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:
- 二叉树的根是数组中的最大元素。
- 左子树是通过数组中最大值左边部分构造出的最大二叉树。
- 右子树是通过数组中最大值右边部分构造出的最大二叉树。
通过给定的数组构建最大二叉树,并且输出这个树的根节点。
Example 1:
输入: [3,2,1,6,0,5]
输入: 返回下面这棵树的根节点:
6
/ \
3 5
\ /
2 0
\
1
注意:
- 给定的数组的大小在 [1, 1000] 之间。
解题思路
这个问题太简单了,直接使用递归。我们先找到最大值以及最大值的位置max_index
,然后对于nums[:max_index]
递归调用函数,返回值为root.left
;对于nums[max_index+1:]
递归调用函数,返回值为root.right
。
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
if nums:
max_val = max(nums)
max_index = nums.index(max_val)
root = TreeNode(max_val)
root.left = self.constructMaximumBinaryTree(nums[:max_index])
root.right = self.constructMaximumBinaryTree(nums[max_index+1:])
return root
我们也可以通过递归来解决这个问题,不过需要使用递减栈。当遍历到的元素值cur
大于栈顶元素的话,我们就将栈中所有小于cur
节点弹出,那么此时全部弹出的值一定在cur
的左子树,我们只需要将最后一个弹出的值记录为node
,令cur.left=node
即可构造树(此时的node
一定是左子树的根)。如果当前遍历到的元素cur
小于栈顶元素的话,我们首先将栈顶元素stack[-1].right=cur
,然后将其加入栈中(注意对于当前遍历到的元素来说,此时的cur
一定是右子树的根)。
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
stack = list()
for n in nums:
cur = TreeNode(n)
while stack and stack[-1].val < n:
cur.left = stack.pop()
if stack:
stack[-1].right = cur
stack.append(cur)
return stack[0]
这个算法要怎么理解呢?假如此时我们通过nums[0] ~ nums[i - 1]
构成了最大二叉树,此时如果在添加一个元素nums[i]
,该添加到哪里呢?我们假设前面的最大二叉树是这样的
此时我们要添加的元素是d
。如果d>a
,那么a
一定是d
的左子树根节点(因为a
在d
的左边,而且a
是左边最大值)
如果d<a
,那么d
一定在a
的右子树,至于在哪?我们只需要找到node<d
的节点,那么以node
为根的子树,一定在d
的左边。(假设node=c
)
从上面可知,当我们新加入一个节点的时候一定要知道前面大于node
的第一个元素是谁?根据之前文章 Leetcode 单调栈问题总结(超详细!!!),所以我们不难知道这里要使用递减栈。最后栈首元素一定是全局最大的,也就是根节点,我们返回它就好啦!
reference:
https://leetcode.com/problems/maximum-binary-tree/discuss/106156/Java-worst-case-O(N)-solution
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!