LeetCode-654. 最大二叉树【栈 树 数组 分治 二叉树 单调栈】

LeetCode-654. 最大二叉树【栈 树 数组 分治 二叉树 单调栈】

  • 题目描述:
  • 解题思路一:递归,这个问题的难点在于如何找到每个子数组的最大值。此处用的是暴力查找最大值,然后递归构建左右子树。
  • 解题思路二:单调栈,显然暴力解法非最优解。可以将任务转化为找出每一个元素左侧和右侧第一个比它大的元素所在的位置。这就是一个经典的单调栈问题了。如果左侧的元素较小,那么该元素就是左侧元素的右子节点;如果右侧的元素较小,那么该元素就是右侧元素的左子节点。细节看代码注释。
  • 解题思路三:0

题目描述:

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

创建一个根节点,其值为 nums 中的最大值。
递归地在最大值 左边 的 子数组前缀上 构建左子树。
递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。

示例 1:
在这里插入图片描述
输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:

  • [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    • [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
      • 空数组,无子节点。
      • [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
        • 空数组,无子节点。
        • 只有一个元素,所以子节点是一个值为 1 的节点。
    • [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
      • 只有一个元素,所以子节点是一个值为 0 的节点。
      • 空数组,无子节点。

示例 2:
在这里插入图片描述
输入:nums = [3,2,1]
输出:[3,null,2,null,1]

提示:

1 <= nums.length <= 1000
0 <= nums[i] <= 1000
nums 中的所有整数 互不相同

解题思路一:递归,这个问题的难点在于如何找到每个子数组的最大值。此处用的是暴力查找最大值,然后递归构建左右子树。

# Definition for a binary tree node.
# 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 construct(left: int, right: int) -> Optional[TreeNode]:
            if left>right: return None
            best = left
            for i in range(left + 1, right + 1):
                if nums[i] > nums[best]: best = i
            
            root = TreeNode(nums[best])
            root.left = construct(left, best - 1)
            root.right = construct(best + 1, right)
            return root

        return construct(0, len(nums)-1)

时间复杂度:O(n2)
空间复杂度:O(n)

解题思路二:单调栈,显然暴力解法非最优解。可以将任务转化为找出每一个元素左侧和右侧第一个比它大的元素所在的位置。这就是一个经典的单调栈问题了。如果左侧的元素较小,那么该元素就是左侧元素的右子节点;如果右侧的元素较小,那么该元素就是右侧元素的左子节点。细节看代码注释。

需要参考LeetCode-496. 下一个更大元素 I【栈 数组 哈希表 单调栈】和LeetCode-503. 下一个更大元素 II【栈 数组 单调栈】
关于更多的解释参考官方题解吧。最大二叉树

# Definition for a binary tree node.
# 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]:
        n = len(nums)
        stk = []
        left, right = [-1] * n, [-1] * n
        tree = [None] * n

        # 维护左右侧大值
        for i in range(n):
            tree[i] = TreeNode(nums[i])
            while stk and nums[i] > nums[stk[-1]]:
                # 右侧大值在出栈时维护
                right[stk[-1]] = i
                stk.pop()
            if stk: 
                # 左侧大值在出栈后维护
                left[i] = stk[-1]
            stk.append(i)
        
        root = None
        for i in range(n):
            # 如果左右都没有大值,说明是根节点
            if left[i] == right[i] == -1:
                root = tree[i]
            # 如果右侧没有大值,或者左侧大值小于右侧大值,那么该节点是左侧大值的右孩子
            elif right[i] == -1 or (left[i] != -1 and nums[left[i]] < nums[right[i]]):
                tree[left[i]].right = tree[i]
            # 如果右侧的元素较小,那么该元素就是右侧元素的左子节点。
            else:
                tree[right[i]].left = tree[i]
        return root

时间复杂度:O(n)
空间复杂度:O(n)

我们还可以把最后构造树的过程放进单调栈求解的步骤中,省去用来存储左右边界的数组。下面的代码理解起来较为困难,同一个节点的左右子树会被多次赋值,读者可以仔细品味其妙处所在。

class Solution:
    def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
        n = len(nums)
        stk = list()
        tree = [None] * n

        for i in range(n):
            tree[i] = TreeNode(nums[i])
            while stk and nums[i] > nums[stk[-1]]:
                tree[i].left = tree[stk[-1]]
                stk.pop()
            if stk:
                tree[stk[-1]].right = tree[i]
            stk.append(i)
        
        return tree[stk[0]]

细细品味💪 💪 💪

解题思路三:0


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/238798.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AOP跨模块捕获异常遭CGLIB拦截而继续向上抛出异常

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、BUG详情 1.1 报错信息 1.2 接口响应信息 1.3 全局异常处理器的定义 二、排查过程 三、解决方案 四、总结 前言 最近&…

element table表格内进行表单验证(简单例子,一看就会,亲测有用~)开箱即用!!

效果图&#xff1a; 代码&#xff1a; <div> <el-form ref"form" :model"form" ><el-table :data"form.tableData" align"center" border><el-table-column label"名称"><template slot-scope&…

nuitka Unknown property box-shadow,transition,transform

nuitka 打包后&#xff0c;控制台的错误解决方法 nuitka --standalone --show-memory --show-progress --nofollow-imports --follow-import-toneed --output-dirout --windows-icon-from-ico./static/test.ico mainUI2.py 由于Qt样式表不是CSS&#xff0c;QSS基于CSS2.1&…

Java | Cannot resolve symbol ‘XXX‘

解决办法 (4种解决方案) 1、先检查pom文件依赖是否报错&#xff0c;报错需重新导入 2、检查jdk版本是否与导入项目的版本一致 Ctrlshiftalts打开 3、重启IDEA&#xff0c;清理缓存 IDEA 无法识别同一个 package 里的其他类&#xff0c;将其显示为红色&#xff0c;但…

【SpringBoot】入门精简

目录 一、初识 SpringBoot 1.1 介绍 1.2 项目创建 1.3 目录结构 1.4 修改配置 二、SpringBoot 集成 2.1 集成 Mybatis框架 2.2 集成 Pagehepler分页插件 2.3 集成 Druid数据库连接池 2.4 集成 Log日志管理 一、初识 SpringBoot 1.1 介绍 Spring Boot是一个用于简化Sp…

Vision Transformer模型架构详解

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

搭建商城系统的构架如何选择?

近期有很多网友在csdn、gitee、知乎的评论区留言&#xff0c;搭建商城系统是选择单体架构还是微服务架构&#xff0c;这里先说结论&#xff0c;如果是纯电商的话&#xff0c;商城系统的架构建议选择单体架构。我们分析下微服务和单体架构的优劣势&#xff0c;就知道了。 一、什…

C语言——结构体

一、结构的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量结构的&#xff0c;每个成员可以是不同类型的变量。 二、结构的声明 struct tag {member-list; }variable-list; 描述一个学生&#xff1a; typedef struct Student {char name[20]; //姓名int age; …

Linux安装MySQL数据库系统

1、MySQL的编译安装。 1.1、准备工作 &#xff08;1&#xff09;为了避免发生端口冲突、程序冲突等现象&#xff0c;建议先查询MySQL软件的安装情况&#xff0c;确认没有使用以RPM方式安装的mysql-server、mysql软件包&#xff0c;否则建议将其卸载。 [rootlocalhost ~]# rp…

关系型数据库-SQLite介绍

优点&#xff1a; 1>sqlite占用的内存和cpu资源较少 2>源代码开源&#xff0c;完全免费 3>检索速度上十几兆、几十兆的数据库sqlite很快&#xff0c;但是上G的时候最慢 4>管理简单&#xff0c;几乎无需管理。灵巧、快速和可靠性高 5>功能简…

【产品设计】软件系统三基座之一:权限管理

不同的员工在公司享有不同的权限&#xff0c;用户可以访问而且只能访问自己被授权的资源。那么&#xff0c;权限管理功能要如何设计呢&#xff1f; 软件系统三基座包含&#xff1a;权限管理、组织架构、用户管理。 何为基座&#xff0c;即是有了这些基础&#xff0c;任一相关的…

边缘计算系统设计与实践

随着科技的飞速发展&#xff0c;物联网和人工智能两大领域的不断突破&#xff0c;我们看到了一种新型的计算模型——边缘计算的崛起。这种计算模型在处理大规模数据、实现实时响应和降低延迟需求方面&#xff0c;展现出了巨大的潜力。本文将深入探讨边缘计算系统的设计原理和实…

13、RockerMQ消息类型之广播与集群消息

RocketMq中提供两种消费模式&#xff1a;集群模式和广播模式。 集群模式 集群模式表示同一个消息会被同一个消费组中的消费者消费一次&#xff0c;消息被负载均衡分配到同一个消费者上的多个实例上。 还有另外一种平均的算法是AllocateMessageQueueAveragelyByCircle&#xff…

windows下docker环境安装

开启硬件虚拟化技术 win10中开启 Hyper-V Win10 下是否开启硬件虚拟化技术&#xff0c;在控制面板&#xff0c;启用 window 功能&#xff0c;找到 Hyper-V 选项&#xff0c;点勾选确认。如图&#xff1a; Windows 11 家庭中文版新增 Hyper-V选项 注意以下的解决方案来自win1…

带你手把手 解读 firejail 沙盒源码(0.9.72版本)目录和组件 (一)

文章目录 关于firejail 的介绍src 目录每个文件夹&#xff08;组件&#xff09;的意义文件目录树 关于firejail 的介绍 Firejail 是一个用于 Linux 系统的安全工具&#xff0c;它通过创建轻量级的沙箱环境来运行应用程序。这种沙箱环境将应用程序与系统其余部分隔离&#xff0…

openEuler 20.03 (LTS-SP2) aarch64 cephadm 部署ceph18.2.0【5】 添加osd存储节点

接上篇 openEuler 20.03 (LTS-SP2) aarch64 cephadm 部署ceph18.2.0【1】离线部署 准备基础环境-CSDN博客 openEuler 20.03 (LTS-SP2) aarch64 cephadm 部署ceph18.2.0【2】离线部署 podman配置registries 部署registry私服 准备离线镜像-CSDN博客 openEuler 20.03 (LTS-SP2…

Python手撕kmeans源码

参考了两篇文章 K-Means及K-Means算法Python源码实现-CSDN博客 使用K-means算法进行聚类分析_kmeans聚类分析结果怎么看-CSDN博客 # 定义kmeans类 from copy import deepcopy from sklearn.datasets import make_blobs import numpy as np import matplotlib.pyplot as pltc…

如何充分准备面试,迅速融入团队并在工作中取得卓越成就

首先&#xff0c;关于如何筹备面试&#xff0c;首先需要对所申请公司与职位进行深入的调查了解&#xff0c;并依据可能提出的面试问题预先准备相应的答案&#xff0c;并提前调试面试所需的仪器设备。同时&#xff0c;也要注重自身形象的塑造。更为关键的是 1. 在计算机领域的面…

redis-学习笔记(Jedis)

自定义的 Redis 客户端 咱们可以实现编写出一个自定义的 Redis 客户端 因为 Redis 公开了自己使用的自定义协议 ---- RESP 协议清楚了, 那么通信数据格式就清除了, 就能完成各层次之间的数据传输, 就能开发服务器和客户端 RESP — Redis 的 序列化 协议 特点: 简单好实现快读进…

ETLCloud的应用策略——实时数据处理是关键

一、ETLCloud是什么&#xff1f; ETLCloud又称数据集成&#xff08;DataOps&#xff09;&#xff0c;是RestCloud旗下的一款数据仓库管理工具&#xff0c;通过自动化数据转换和集成来实现企业内部和外部数据的无缝对接&#xff0c;从而帮助企业快速获取准确的数据信息&#xff…