题目链接
思路一:递归
分析:题目就是让找出每次在范围内的最大值为根节点
代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
//最大值所在的下标
int maxIndex = 0;
//最大值
int max = -1;
for(int i = 0 ; i < nums.length;i++){
if(max < nums[i]){
max = nums[i];
maxIndex = i;
}
}
//这就是最后的根节点
TreeNode res = new TreeNode(max);
//递归 找出左子树的根节点
res.left = divide(nums,0,maxIndex-1);
//递归找出右子树的根节点
res.right = divide(nums,maxIndex+1,nums.length-1);
return res;
}
//递归找出在[left,right]范围内的最大值作为根节点
public TreeNode divide(int[] nums,int left,int right){
//找到出口条件
if(left>right){
return null;
}
//和上面的代码同理,找到最大的
int maxIndex = -1;
int max = -1;
for(int i = left;i<=right;i++){
if(max<nums[i]){
max = nums[i];
maxIndex = i;
}
}
//这是在这个范围内的根节点
TreeNode root = new TreeNode(max);
//同理
root.left = divide(nums, left,maxIndex-1);
root.right = divide(nums,maxIndex+1,right);
//返回此时的根节点
return root;
}
}
最坏时间复杂度:O(n2)
思路二:单调栈
要找最大的作为根节点,那么我们需要一个栈底到栈顶依次减小的单调栈,当遇到栈顶小于当前元素时:
分析:此时的栈顶肯定在当前元素的左子树里面,但不一定就是当前元素左子树的根节点,因为不一定是当前元素左边元素中最大的,所以先取出当前元素,看看栈内下一个元素。
情况一:下一个元素要是比当前元素小:此时(top0<cur && top1 < cur && top0 < top1),此时应该是top0是top1的右子树节点,然后又回到了前面的情况,此时栈顶元素依然小于当前元素。
情况二:下一个元素要是比当前元素大,那么就说明,刚刚取出来的栈顶元素肯定就是当前元素的左子树的根节点,因为栈内下一个元素就比当前元素大了,那么当前元素的左子树根节点指向刚刚的栈顶元素,然后将当前元素放入栈顶。
最后,局部最大的元素都在栈内了,最大的在栈底。
从栈顶开始遍历,栈顶的依次是下面元素的右子树根节点。
代码:
public TreeNode constructMaximumBinaryTree(int[] nums) {
int len = nums.length;
int top = -1;
TreeNode[] stack = new TreeNode[len];
//当前节点
TreeNode curNode = null;
for(int i = 0 ; i < len;i++){
curNode = new TreeNode(nums[i]);
//如果当前栈不为空,并且当前栈顶元素小于当前节点
while (top!=-1 && stack[top].val < curNode.val){
//取出当前栈顶元素
TreeNode topNode = stack[top--];
//栈不空,并且当前栈顶元素依然小于当前元素 说明刚刚那个栈顶只是当前栈顶的一个右节点,而不是当前元素的左节点
if(top!=-1 && stack[top].val < curNode.val){
//当前栈顶元素的元素就是之前的栈顶元素
stack[top].right = topNode;
}else{
//否则,当前元素的左节点就是之前的栈顶
curNode.left = topNode;
}
}
//当前元素入栈
stack[++top] = curNode;
}
//此时最大的元素在栈底, 从栈顶开始遍历
while (top!=-1){
//取出栈顶元素
curNode = stack[top--];
if(top!=-1){
//此时的栈顶的右节点就是之前的栈顶元素
stack[top].right = curNode;
}
}
return curNode;
}
以防小伙伴还是看不懂,下面图解:
nums={3,2,1,6,0,5}
栈空,直接进
栈顶大于当前元素,也入栈
栈顶大于当前元素,也入栈
此时当前元素大于栈顶元素
栈顶元素出栈
此时栈顶元素依然小于之前的栈顶元素(topNode)
此时的栈顶元素的右子树根节点就是刚刚的栈顶元素
此时栈顶元素还是小于当前元素,出栈
此时栈顶依然小于当前元素,刚刚的栈顶是此时栈顶的右子树根节点
同理,出栈
此时栈空,此时刚刚的栈顶元素就是当前元素的左子树的根节点:
栈空,入栈
此时栈顶大于当前元素,入栈
此时当前元素5大于栈顶0
0出栈,5小于6,然后0就是5的左子树根节点
当前元素5小于栈顶元素6,入栈
此时栈内只有两个元素,5,6,从栈顶开始遍历,上面的一定是下面的右子树。
结束。