LeetCode 654.最大二叉树

LeetCode 654.最大二叉树

1、题目

题目链接:654. 最大二叉树

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

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

返回 nums 构建的 最大二叉树

示例 1:
image.png

输入: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:
image.png

输入:nums = [3,2,1]
输出:[3,null,2,null,1]

提示:

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

2、递归(前序)

思路

构造树一般采用的是前序遍历,因为先构造中间节点,然后递归构造左子树和右子树。

  1. 确定递归函数的参数和返回值

参数传入的是存放元素的数组,返回该数组构造的二叉树的头结点,返回类型是指向节点的指针。
代码如下:

TreeNode* constructMaximumBinaryTree(vector<int>& nums)
  1. 确定终止条件

题目中说了输入的数组大小一定是大于等于1的,所以我们不用考虑小于1的情况,那么当递归遍历的时候,如果传入的数组大小为1,说明遍历到了叶子节点了。
那么应该定义一个新的节点,并把这个数组的数值赋给新的节点,然后返回这个节点。 这表示一个数组大小是1的时候,构造了一个新的节点,并返回。
代码如下:

TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {node->val = nums[0];return node;
}
  1. 确定单层递归的逻辑

这里有三步工作

  1. 先要找到数组中最大的值和对应的下标, 最大的值构造根节点,下标用来下一步分割数组。

代码如下:

int maxValue = 0;
int maxIndex = 0;
for (int i = 0; i < nums.size(); i++) {if (nums[i] > maxValue) {maxValue = nums[i];maxIndex = i;}
}
TreeNode* node = new TreeNode(0);
node->val = maxValue;
  1. 最大值所在的下标左区间 构造左子树

这里要判断 maxIndex > 0,因为要保证左区间至少有一个数值。
代码如下:

if (maxIndex > 0) {vector<int> newVec(nums.begin(), nums.begin() + maxIndex);node->left = constructMaximumBinaryTree(newVec);
}
  1. 最大值所在的下标右区间 构造右子树

判断maxIndex < (nums.size() - 1),确保右区间至少有一个数值。
代码如下:

if (maxValueIndex < (nums.size() - 1)) {vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());node->right = constructMaximumBinaryTree(newVec);
}

代码

class Solution {
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {// 创建一个值为0的节点作为根节点TreeNode* node = new TreeNode(0);// 如果数组只有一个元素if (nums.size() == 1) {// 将根节点的值设置为数组的唯一元素node->val = nums[0];// 返回根节点return node;}// 初始化最大值和最大值的索引int maxValue = 0;int maxIndex = 0;// 遍历数组找到最大值和最大值的索引for (int i = 0; i < nums.size(); i++) {if (nums[i] > maxValue) {maxValue = nums[i];maxIndex = i;}}// 将根节点的值设置为最大值node->val = nums[maxIndex];// 如果最大值索引大于0,说明左子树非空if (maxIndex > 0) {// 截取数组中的左子树部分vector<int> newVec(nums.begin(), nums.begin() + maxIndex);// 递归构建左子树node->left = constructMaximumBinaryTree(newVec);}// 如果最大值索引小于数组长度减1,说明右子树非空if (maxIndex < nums.size() - 1) {// 截取数组中的右子树部分vector<int> newVec(nums.begin() + maxIndex + 1, nums.end());// 递归构建右子树node->right = constructMaximumBinaryTree(newVec);}// 返回根节点return node;}
};

复杂度分析

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(n)

3、递归(使用索引)

思路

代码

class Solution {
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {return construct(nums, 0, nums.size());}TreeNode* construct(vector<int>& nums, int left, int right) {// 如果左边界大于等于右边界,返回空指针if (left >= right) {return nullptr;}// 找到数组中最大元素的索引作为分割点int maxIndex = left;for (int i = left; i < right; i++) {if (nums[i] > nums[maxIndex]) {maxIndex = i;}}// 创建当前最大元素为根节点的树节点TreeNode* node = new TreeNode(nums[maxIndex]);// 递归构造左子树node->left = construct(nums, left, maxIndex);// 递归构造右子树node->right = construct(nums, maxIndex + 1, right);// 返回根节点return node;}
};

复杂度分析

  • 时间复杂度: O(n^2)
  • 空间复杂度: O(n)

4、单调栈

思路

代码

class Solution {
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {int n = nums.size();vector<int> stk;vector<int> left(n, -1), right(n, -1);vector<TreeNode*> tree(n);for (int i = 0; i < n; ++i) {tree[i] = new TreeNode(nums[i]);// 如果栈不为空且当前数字大于栈顶元素,则将当前数字作为栈顶元素的右子树while (!stk.empty() && nums[i] > nums[stk.back()]) {right[stk.back()] = i;stk.pop_back();}// 如果栈不为空,则将当前数字作为栈顶元素的左子树if (!stk.empty()) {left[i] = stk.back();}stk.push_back(i);}TreeNode* root = nullptr;for (int i = 0; i < n; ++i) {// 如果当前节点的左右子树都为空,则该节点为根节点if (left[i] == -1 && right[i] == -1) {root = tree[i];}// 如果当前节点的右子树为空或者左子树的值小于右子树的值,则将当前节点作为左子树的右子树else if (right[i] == -1 || (left[i] != -1 && 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)

5、单调栈(优化)

思路

我们还可以把最后构造树的过程放进单调栈求解的步骤中,省去用来存储左右边界的数组。

代码

lass Solution {
public:TreeNode* constructMaximumBinaryTree(vector<int>& nums) {int n = nums.size();vector<int> stk;vector<TreeNode*> tree(n);// 遍历数组中的每个元素for (int i = 0; i < n; ++i) {// 创建一个新的树节点tree[i] = new TreeNode(nums[i]);// 当栈不为空且当前元素大于栈顶元素时while (!stk.empty() && nums[i] > nums[stk.back()]) {// 将当前节点的左子节点指向栈顶元素对应的树节点tree[i]->left = tree[stk.back()];// 弹出栈顶元素stk.pop_back();}// 如果栈不为空,则将栈顶元素对应的树节点的右子节点指向当前节点if (!stk.empty()) {tree[stk.back()]->right = tree[i];}// 将当前元素的索引压入栈中stk.push_back(i);}// 返回栈底元素对应的树节点作为整棵树的根节点return tree[stk[0]];}
};

复杂度分析

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

11、关系运算符、逻辑运算符(讲解 和 的区别)、赋值表达式、三目表达式、运算符优先级(超详细版本)+结合性的分析

这里写目录标题 一、关系运算符&#xff08;比较运算符&#xff09;二、⭐逻辑运算符1、 && 和 &2、|| 或 |3、&#xff01;4、^ 三、赋值运算符四、三目运算符&#xff08;条件运算符&#xff09;五、运算符优先级 在讲之前先明确几个概念&#xff1a; 1、单目运算…

【人工智能基础】GAN与WGAN实验

一、GAN网络概述 GAN&#xff1a;生成对抗网络。GAN网络中存在两个网络&#xff1a;G&#xff08;Generator&#xff0c;生成网络&#xff09;和D&#xff08;Discriminator&#xff0c;判别网络&#xff09;。 Generator接收一个随机的噪声z&#xff0c;通过这个噪声生成图片…

阿里开源编程大模型 CodeQwen1.5:64K92编程语言,Code和SQL编程,评测接近GPT-4-Turbo

前言 阿里巴巴最近发布的CodeQwen1.5模型标志着其在编程语言模型领域的一次重大突破。这款开源模型不仅支持高达92种编程语言和64K的上下文长度&#xff0c;而且在多项性能评测中显示出接近或超过当前行业领导者GPT-4-Turbo的能力。 Huggingface模型下载&#xff1a;https://h…

Boost库的使用

1 下载与安装 1.1 下载 网址&#xff1a;Boost C Libraries 进入后选择自己需要的版本安装即可 1.2 安装 1.2.1 解压 1.2.2 编译安装 双击bootstrap.bat 这一步完成后会生成一个b2.exe文件 双击b2.exe文件运行&#xff08;此步需要花费较长的时间&#xff09; 之后再stag…

双向链表(双向带头循环)的增删查改的实现(简单易懂)

一&#xff1a;双向链表的概念 每个节点除开存有数据&#xff0c;还有一个指针指向前一个节点&#xff0c;一个指针指向后一个节点&#xff0c;尾节点和哨兵位互相指向&#xff0c;从而形成一个循环。 二&#xff1a;双向链表的实现第一点&#xff1a; 本文采用三个文件进行实…

GIS数据—1984-2020中国1km人造夜间灯光观测数据

夜间灯光观测数据&#xff08;Nighttime Light,NTL&#xff09;是评估人类活动边界的常用手段&#xff0c;目前&#xff0c;该数据已经广泛应用于城市范围、不透水面、基础设施建设等一系列过程。今天&#xff0c;小编要带来的是长时间序列中国区域边界的夜间灯光观测数据。 数…

springcloud -nacos实战

一、nacos 功能简介 1.1.什么是Nacos&#xff1f; 官方简介&#xff1a;一个更易于构建云原生应用的动态服务发现(Nacos Discovery )、服务配置(Nacos Config)和服务管理平台。 Nacos的关键特性包括&#xff1a; 服务发现和服务健康监测动态配置服务动态DNS服务服务及其元数…

VMware配置Kali linux + 物理机连接Xshell

VMware 配置 kali linux 首先需要先安装VMware Workstation 我是在Windows 安装的 VMware Workstation Pro 17 虚拟化&#xff0c;产品密钥。。这里不做多说了 下载kali linux 这里我下载的是kali-linux-2024.1 Note&#xff1a;这里选Virtual Machines&#xff0c;建议不要…

景源畅信:抖音小店的商品怎么同步到橱窗?

在数字营销的海洋中&#xff0c;抖音小店与橱窗的同步操作无疑是商家们关注的焦点。这不仅能增加商品的曝光度&#xff0c;还能提高交易的可能性。那么&#xff0c;如何将抖音小店的商品同步到橱窗呢? 一、核心步骤解析 要实现商品从抖音小店同步到橱窗&#xff0c;你需要确保…

【Linux 网络】网络编程套接字 -- 详解

⚪ 预备知识 1、理解源 IP 地址和目的 IP 地址 举例理解&#xff1a;&#xff08;唐僧西天取经&#xff09; 在 IP 数据包头部中 有两个 IP 地址&#xff0c; 分别叫做源 IP 地址 和目的 IP 地址。 如果我们的台式机或者笔记本没有 IP 地址就无法上网&#xff0c;而因为…

Unity引擎是什么?有哪些优点

大家好&#xff0c;我是咕噜土豆&#xff0c;很高兴又和大家见面了。今天我们一起来了解一下Unity引擎和它有哪些优点。 首先带大家了解什么是Unity引擎 Unity引擎是一款由Unity Technologies开发的跨平台游戏开发引擎&#xff0c;广泛用于创建2D和3D游戏以及其他交互式内容&…

C++动态内存区域划分、new、delete关键字

目录 一、C/C中程序的内存区域划分 为什么会存在内存区域划分&#xff1f; 二、new关键字 1、内置类型的new/delete使用方法&#xff1a; 2、new和delete的本质 一、C/C中程序的内存区域划分 为什么会存在内存区域划分&#xff1f; 因为不同数据有不同的存储需求&#xff0…

【SpringBoot记录】从基本使用案例入手了解SpringBoot-数据访问(1)

前言 在程序开发尤其是网页应用开发中&#xff0c;数据访问是必不可少的。通过前面的基本案例我们完成了一个简单的SpringBoot Web应用并对自动配置原理有了一定了解&#xff0c;本节在上述案例基础上&#xff0c;继续编写数据访问案例&#xff0c;将通过SpringBoot中数据访问…

音视频开发6 音视频录制原理和播放原理

音视频录制原理 音视频播放原理

# 电脑突然连接不上网络了,怎么办?

电脑突然连接不上网络了&#xff0c;怎么办&#xff1f; 一、原因分析&#xff1a; 1、IP 地址冲突 2、DNS 解析出现问题。 3、电脑网络设置是否打开了【移动热点】或【飞行模式】。 4、【WLAN AutoConfig】服务是否打开。 5、无线网卡驱动损坏。 6、检查 WIFI 开关是否…

HTML+VUE3组合式+ELEMENT的容器模板示例(含侧栏导航,表格,...)

一个简单的在html中使用Vue3及Element-plus vue-icons的整合示例&#xff1a; 一、示例截图 二、文件代码 直接复制到html文件在浏览器打开即可预览 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title&g…

CCleaner系统优化与隐私保护工具,中文绿色便携版 v6.23.11010

01 软件介绍 CCleaner 是一款高级的系统优化工具&#xff0c;其设计宗旨在于彻底清理 Windows 操作系统中积累的无用文件和冗余的注册表项。此举旨在显著提升计算机的运行效率并回收磁盘空间。该软件拥有高效的能力&#xff0c;可以清除包括临时文件、浏览器缓存及其历史记录在…

08 - hive的集合函数、高级聚合函数、炸裂函数以及窗口函数

目录 1、集合函数 1.1、size&#xff1a;集合中元素的个数 1.2、map&#xff1a;创建map集合 1.3、map_keys&#xff1a; 返回map中的key 1.4、map_values: 返回map中的value 1.5、array 声明array集合 1.6、array_contains: 判断array中是否包含某个元素 1.7、sort_a…

UIKit之UIButton

功能需求&#xff1a; 点击按钮切换按钮的文字和背景图片&#xff0c;同时点击上下左右可以移动图片位置&#xff0c;点击加或减可以放大或缩小图片。 分析&#xff1a; 实现一个UIView的子类即可&#xff0c;该子类包含多个按钮。 实现步骤&#xff1a; 使用OC语言&#xf…

HCIP的学习(14)

过滤策略—filter-policy ​ 思科中&#xff1a;分发列表 ​ 过滤策略是只能够针对于路由信息进行筛选&#xff08;过滤&#xff09;的工具&#xff0c;而无法针对于LSA进行过滤。 在R4的出方向上配置过滤策略&#xff0c;使得R1不能学习到23.0.0.0/24路由信息1、抓取流量 […