java数据结构与算法刷题-----LeetCode654. 最大二叉树

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

在这里插入图片描述
在这里插入图片描述

1. 法一:单调栈

注意:单调栈比递归方法难理解的多,单调栈时间复杂度为O(n),递归方法的时间复杂度为O( n 2 n^2 n2). 实际工作场景中,单调栈的效率肯定更高,但是这是做题,因为测试用例的数量较少,反而会比下面递归方法花费的时间更多。所以不要因为提交后发现这个算法效率没有递归的高就放弃掌握此方法。

解题思路:时间复杂度O(n),空间复杂度O(n)
  1. 利用单调栈来处理
  2. 每一个结点都要入栈,但是入栈前:
  1. 如果栈中已经入栈的,都比它小,说明他就是一个中间结点,那么栈中的元素应该是他的左区间,应该成为它的左子树
  2. 如果栈中已经入栈的,比当前要入栈的结点node大,说明,node应该成为人家栈顶元素的右子树。
  1. 最终返回栈低那个最大的元素,就是构造完成的二叉树的根节点

图解如下:

  1. 第一个元素可以无脑入栈
    在这里插入图片描述
  2. 第二个元素,2,入栈时发现栈顶元素3比它大,说明2应该是栈顶右子树,然后栈顶元素指向2
    在这里插入图片描述
  3. 第三个元素,1,入栈时发现栈顶元素2,比它大,说明1应该是栈顶元素右子树,然后栈顶元素指向1.
    在这里插入图片描述
  4. 第4个元素,6
  1. 入栈时发现栈顶为1,比它小,则出栈1,成为其左子树
    在这里插入图片描述
  2. 然后发现新的栈顶2依然比它小,继续出栈成为其左子树
    在这里插入图片描述
  3. 然后发现栈顶3依然比它小,继续出栈成为其左子树,然后栈空了,将6入栈,此时栈中只有一个6结点
    在这里插入图片描述
  1. 第5个元素,0,入栈时发现比栈顶6小,成为其右子树然后入栈
    在这里插入图片描述
  2. 第6个元素,5
  1. 入栈时发现比栈顶0大,则0出栈成为其左子树
    在这里插入图片描述
  2. 然后发现,栈顶的6比它大,它就得成为6的右子树,然后入栈
    在这里插入图片描述

此时,完成了遍历,二叉树也构造完成,栈中的元素为[6,5],其中5是栈顶。而栈低必然是根节点6.所以最后我们得返回栈低的6

代码

在这里插入图片描述

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        if(nums.length == 0) return null;
        if(nums.length == 1) return new TreeNode(nums[0]);
        int n = nums.length;
        //单调栈,结点入栈前,如果栈中元素比它小,栈中元素成为其左子树,如果栈中元素比它大,它成为栈顶元素右子树
        TreeNode[] stack = new TreeNode[n];
        int index = -1;//栈顶指针,初始-1
        for (int i = 0; i < n; ++i) {//依次遍历结点
            TreeNode node = new TreeNode(nums[i]);//将数字变为TreeNode结点
            while (index > -1 && nums[i] > stack[index].val) {//如果栈中结点,比它小,成为其左子树
                node.left = stack[index--];//出栈成为其左子树
            }
            if (index>-1) {//如果栈中元素比它大,或者等于它
                stack[index].right = node;//它必须成为其右子树
            }
            stack[++index] = node;//最后将此结点也入栈,以便下一个结点处理与它的关系
        }
        return stack[0];//最终"栈低"一定会留有一个根节点。
    }
}

2. 法二:递归

解题思路:时间复杂度O( n 2 n^2 n2),空间复杂度O(n)
  1. 划分区间,每次找区间最大值,然后再次以它为中心,划分两个区间
  2. 初始区间是整个数组,找到最大值后,以它为中心划分两个区间再次递归
  3. 左边区间是它的左节点,右边区间是它的右节点
代码

在这里插入图片描述

/**
 * 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) {
        return constructMaximumBinaryTree(nums,0,nums.length-1);

    }
    public TreeNode constructMaximumBinaryTree(int[] nums,int left,int right) {
        if(right < left) return null;
        if(right == left ) return new TreeNode(nums[left]);//right和left指向同一个结点直接返回
        //找到区间[left,right]的最大值作为中间结点
        int maxIndex = left;
        for(int i = left+1;i<=right;i++)
            if(nums[i]>nums[maxIndex]) maxIndex = i;
            
        //构建中间结点
        TreeNode node = new TreeNode(nums[maxIndex]);
        //左区间构建左子树,右区间构建右子树
        node.left = constructMaximumBinaryTree(nums,left,maxIndex-1);
        node.right = constructMaximumBinaryTree(nums,maxIndex+1,right);
        return node;
    }
}
  • 49
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值