二叉搜索树题目:将有序数组转换为二叉搜索树

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 证明
    • 代码
    • 复杂度分析

题目

标题和出处

标题:将有序数组转换为二叉搜索树

出处:108. 将有序数组转换为二叉搜索树

难度

4 级

题目描述

要求

给定整数数组 nums \texttt{nums} nums,其中元素已经按升序排列,将其转换为高度平衡二叉搜索树。

高度平衡二叉树满足每个结点的左右子树的高度差的绝对值不超过 1 \texttt{1} 1

示例

示例 1:

示例 1.1

输入: nums = [-10,-3,0,5,9] \texttt{nums = [-10,-3,0,5,9]} nums = [-10,-3,0,5,9]
输出: [0,-3,9,-10,null,5] \texttt{[0,-3,9,-10,null,5]} [0,-3,9,-10,null,5]
解释: [0,-10,5,null,-3,null,9] \texttt{[0,-10,5,null,-3,null,9]} [0,-10,5,null,-3,null,9] 也将被视为正确答案:

示例 1.2

示例 2:

示例 2

输入: nums = [1,3] \texttt{nums = [1,3]} nums = [1,3]
输出: [3,1] \texttt{[3,1]} [3,1]
解释: [1,null,3] \texttt{[1,null,3]} [1,null,3] [3,1] \texttt{[3,1]} [3,1] 都是高度平衡二叉搜索树。

数据范围

  • 1 ≤ nums.length ≤ 10 4 \texttt{1} \le \texttt{nums.length} \le \texttt{10}^\texttt{4} 1nums.length104
  • -10 4 ≤ nums[i] ≤ 10 4 \texttt{-10}^\texttt{4} \le \texttt{nums[i]} \le \texttt{10}^\texttt{4} -104nums[i]104
  • nums \texttt{nums} nums严格递增顺序排列

解法

思路和算法

由于二叉搜索树的中序遍历序列是单调递增的,因此给定的升序数组即为二叉搜索树的中序遍历序列。在只有中序遍历序列的情况下,无法唯一地确定二叉搜索树。

为了得到高度平衡二叉搜索树,构造的二叉搜索树应满足根结点的左子树和右子树的结点数尽可能接近。当结点总数是奇数时,根结点值应为中序遍历序列的中间位置的结点值,根结点的左子树和右子树的结点数应相等;当结点总数是偶数时,根结点值应为中序遍历序列的中间位置的两个结点值之一,根结点的左子树和右子树的结点数之差的绝对值应等于 1 1 1

确定高度平衡二叉搜索树的根结点之后,其余的结点值分别位于根结点的左子树和右子树中,数组中位于根结点左侧的值都在左子树中,数组中位于根结点右侧的值都在右子树中,左子树和右子树也是高度平衡二叉搜索树。可以通过数学归纳法证明,如果两个高度平衡二叉搜索树的结点数之差的绝对值不超过 1 1 1,则这两个高度平衡二叉搜索树的高度之差的绝对值不超过 1 1 1

由于高度平衡二叉搜索树的每个子树也都是高度平衡二叉搜索树,每个子树包含的结点值的集合对应给定的数组中的连续子数组,因此可以使用递归的方式构造高度平衡二叉搜索树,递归的过程中只要指定每个子树包含的结点值的集合对应的连续子数组的下标区间 [ start , end ] [\textit{start}, \textit{end}] [start,end] 即可。

递归的终止条件是下标区间为空,即 start > end \textit{start} > \textit{end} start>end,此时对应的子树为空。对于其余情况,首先根据 start \textit{start} start end \textit{end} end 计算得到根结点值的下标 mid \textit{mid} mid 并使用该结点值创建根结点,然后分别使用下标区间 [ start , mid − 1 ] [\textit{start}, \textit{mid} - 1] [start,mid1] [ mid + 1 , end ] [\textit{mid} + 1, \textit{end}] [mid+1,end] 创建根结点的左子树和右子树。

start ≤ end \textit{start} \le \textit{end} startend 时, mid \textit{mid} mid 的取值的唯一性取决于下标区间 [ start , end ] [\textit{start}, \textit{end}] [start,end] 内的元素个数的奇偶性。如果下标区间 [ start , end ] [\textit{start}, \textit{end}] [start,end] 内的元素个数是奇数,则 mid \textit{mid} mid 的取值是唯一的;如果下标区间 [ start , end ] [\textit{start}, \textit{end}] [start,end] 内的元素个数是偶数,则 mid \textit{mid} mid 的取值是不唯一的,可以是中间位置左边的下标或者中间位置右边的下标。

  • mid = ⌊ start + end 2 ⌋ \textit{mid} = \Big\lfloor \dfrac{\textit{start} + \textit{end}}{2} \Big\rfloor mid=2start+end 时, mid \textit{mid} mid 是中间位置左边的下标。

  • mid = ⌊ start + end + 1 2 ⌋ \textit{mid} = \Big\lfloor \dfrac{\textit{start} + \textit{end} + 1}{2} \Big\rfloor mid=2start+end+1 时, mid \textit{mid} mid 是中间位置右边的下标。

如果下标区间 [ start , end ] [\textit{start}, \textit{end}] [start,end] 内的元素个数是奇数,则上述两种方法计算得到的 mid \textit{mid} mid 的值相同。

由此可以得到三种构造高度平衡二叉搜索树的方法。

  • 每次都将根结点值取为中间位置左边的下标处的值。

  • 每次都将根结点值取为中间位置右边的下标处的值。

  • 每次随机将根结点值取为中间位置左边或右边的下标处的值。

证明

为了证明上述构造高度平衡二叉搜索树的方法的正确性,需要证明:如果两个高度平衡二叉搜索树的结点数之差的绝对值不超过 1 1 1,则这两个高度平衡二叉搜索树的高度之差的绝对值不超过 1 1 1

h ( n ) h(n) h(n) 表示有 n n n 个结点的高度平衡二叉搜索树的高度,其中 n ≥ 1 n \ge 1 n1,规定 h ( 1 ) = 0 h(1) = 0 h(1)=0 h ( 2 ) = h ( 3 ) = 1 h(2) = h(3) = 1 h(2)=h(3)=1,则对于 1 ≤ n ≤ 3 1 \le n \le 3 1n3 h ( n ) = ⌊ log ⁡ n ⌋ h(n) = \lfloor \log n \rfloor h(n)=logn

n ≥ 4 n \ge 4 n4 时,假设对于任意 1 ≤ m < n 1 \le m < n 1m<n 都有 h ( m ) = ⌊ log ⁡ m ⌋ h(m) = \lfloor \log m \rfloor h(m)=logm,需要证明 h ( n ) = ⌊ log ⁡ n ⌋ h(n) = \lfloor \log n \rfloor h(n)=logn

  • n n n 是奇数时,令 n = 2 k + 1 n = 2k + 1 n=2k+1,其中 k ≥ 1 k \ge 1 k1,则根结点的左子树和右子树各有 k k k 个结点。由于 k < n k < n k<n,因此 h ( k ) = ⌊ log ⁡ k ⌋ h(k) = \lfloor \log k \rfloor h(k)=logk 已知,此时 h ( n ) = h ( k ) + 1 = ⌊ log ⁡ k ⌋ + 1 h(n) = h(k) + 1 = \lfloor \log k \rfloor + 1 h(n)=h(k)+1=logk+1。由于 n = 2 k + 1 n = 2k + 1 n=2k+1,因此 n − 1 = 2 k n - 1 = 2k n1=2k log ⁡ ( n − 1 ) = log ⁡ 2 k = log ⁡ k + 1 \log (n - 1) = \log 2k = \log k + 1 log(n1)=log2k=logk+1,取整得 ⌊ log ⁡ ( n − 1 ) ⌋ = ⌊ log ⁡ k ⌋ + 1 \lfloor \log (n - 1) \rfloor = \lfloor \log k \rfloor + 1 log(n1)⌋=logk+1。由于 n n n 是奇数,因此 ⌊ log ⁡ n ⌋ = ⌊ log ⁡ ( n − 1 ) ⌋ \lfloor \log n \rfloor = \lfloor \log (n - 1) \rfloor logn=log(n1)⌋ ⌊ log ⁡ n ⌋ = ⌊ log ⁡ k ⌋ + 1 \lfloor \log n \rfloor = \lfloor \log k \rfloor + 1 logn=logk+1 h ( n ) = ⌊ log ⁡ n ⌋ h(n) = \lfloor \log n \rfloor h(n)=logn

  • n n n 是偶数时,令 n = 2 k + 2 n = 2k + 2 n=2k+2,其中 k ≥ 1 k \ge 1 k1,则根结点的左子树和右子树分别有 k k k 个结点和 k + 1 k + 1 k+1 个结点。由于 k + 1 < n k + 1 < n k+1<n,因此 h ( k + 1 ) = ⌊ log ⁡ ( k + 1 ) ⌋ h(k + 1) = \lfloor \log (k + 1) \rfloor h(k+1)=log(k+1)⌋ 已知,此时 h ( n ) = h ( k + 1 ) + 1 = ⌊ log ⁡ ( k + 1 ) ⌋ + 1 h(n) = h(k + 1) + 1 = \lfloor \log (k + 1) \rfloor + 1 h(n)=h(k+1)+1=log(k+1)⌋+1。由于 n = 2 k + 2 = 2 ( k + 1 ) n = 2k + 2 = 2(k + 1) n=2k+2=2(k+1),因此 log ⁡ n = log ⁡ 2 ( k + 1 ) = log ⁡ ( k + 1 ) + 1 \log n = \log 2(k + 1) = \log (k + 1) + 1 logn=log2(k+1)=log(k+1)+1,取整得 ⌊ log ⁡ n ⌋ = ⌊ log ⁡ ( k + 1 ) ⌋ + 1 \lfloor \log n \rfloor = \lfloor \log (k + 1) \rfloor + 1 logn=log(k+1)⌋+1 h ( n ) = ⌊ log ⁡ n ⌋ h(n) = \lfloor \log n \rfloor h(n)=logn

因此对于任意正整数 n n n,都有 h ( n ) = ⌊ log ⁡ n ⌋ h(n) = \lfloor \log n \rfloor h(n)=logn。由于任意两个相邻正整数的对数之差一定不超过 1 1 1,因此当 n ≥ 2 n \ge 2 n2 时,一定有 h ( n ) − h ( n − 1 ) ≤ 1 h(n) - h(n - 1) \le 1 h(n)h(n1)1

代码

下面的代码为每次都将根结点值取为中间位置左边的下标处的值的做法。

class Solution {public TreeNode sortedArrayToBST(int[] nums) {return createBST(nums, 0, nums.length - 1);}public TreeNode createBST(int[] nums, int start, int end) {if (start > end) {return null;}int mid = (end - start) / 2 + start;return new TreeNode(nums[mid], createBST(nums, start, mid - 1), createBST(nums, mid + 1, end));}
}

下面的代码为每次都将根结点值取为中间位置右边的下标处的值的做法。

class Solution {public TreeNode sortedArrayToBST(int[] nums) {return createBST(nums, 0, nums.length - 1);}public TreeNode createBST(int[] nums, int start, int end) {if (start > end) {return null;}int mid = (end - start + 1) / 2 + start;return new TreeNode(nums[mid], createBST(nums, start, mid - 1), createBST(nums, mid + 1, end));}
}

下面的代码为每次随机将根结点值取为中间位置左边或右边的下标处的值的做法。

class Solution {public TreeNode sortedArrayToBST(int[] nums) {return createBST(nums, 0, nums.length - 1);}public TreeNode createBST(int[] nums, int start, int end) {if (start > end) {return null;}int mid = (end - start + (int) (Math.random() * 2)) / 2 + start;return new TreeNode(nums[mid], createBST(nums, start, mid - 1), createBST(nums, mid + 1, end));}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。每个元素都被访问一次。

  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。空间复杂度主要是递归调用的栈空间,由于构造的是高度平衡二叉搜索树,因此递归调用栈的深度是 O ( log ⁡ n ) O(\log n) O(logn)。注意返回值不计入空间复杂度。

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

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

相关文章

一、低代码平台-数据库设计规范

数据库设计规范目的 a、规格化管理各个业务数据表 b、通过字段名称快速了解表与表之间的关联关系 c、通过字段第一位快速了解字段数据类型等等所有规范都为了更好的开发与后期系统运维。 1、数据库设计规范 答&#xff1a;数据库安装必须选择大小写敏感&#xff1b;编码格式…

15 easy 141. 环形链表

法1&#xff1a;快慢指针法&#xff1a; //给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 // // 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数…

Python爬虫副业真的可行吗?

首先回答你&#xff0c;是可行的&#xff0c;python爬虫能当副业&#xff0c;副业的方式比较多&#xff0c;等下我会讲几种。 那学到哪个层次可以接单呢&#xff1f;主要看你是接什么样的单&#xff0c;爬一些资料&#xff0c;视频这种简单的学一两个月就没什么问题&#xff0…

第一天 走进Docker的世界

第一天 走进Docker的世界 介绍docker的前世今生&#xff0c;了解docker的实现原理&#xff0c;以Django项目为例&#xff0c;带大家如何编写最佳的Dockerfile构建镜像。通过本章的学习&#xff0c;大家会知道docker的概念及基本操作&#xff0c;并学会构建自己的业务镜像&…

一文读懂Persistence One- 如何将Restaking带入Cosmos

Persistence One正在将Restaking引入Cosmos。用户将能够通过pSTAKE、Stride、Quicksilver和Milkyway将Liquid Staked Tokens&#xff08;如ATOM、TIA、DYDX等&#xff09;存入Persistence One&#xff0c;对其进行Restaking&#xff0c;从而安全地连接更多区块链&#xff0c;首…

MySQL:数据库中有哪些锁

1、全局锁 加上全局锁后整个数据库就处于只读状态了&#xff0c;这时其他线程执行以下操作&#xff0c;都会被阻塞&#xff1a; 对数据的增删改操作&#xff0c;比如 insert、delete、update等语句&#xff1b;对表结构的更改操作&#xff0c;比如 alter table、drop table 等…

Android APK包反编译为java文件教程

方法 流程&#xff1a; test.apk -> smali文件 -> dex文件 -> jar文件 ->java 文件 将APK包解压为 smail文件 下载 apktool工具 apktool.jar 将 test.apk 和 apktool.jar放同一目录下&#xff0c;并执行以下命令 java -jar apktool.jar d -f xxx.apk -o xxx(解…

【如何像网吧一样弄个游戏菜单在家里】

GGmenu 个人家庭版游戏、应用管理 桌面图标管理器

[环境配置]ssh连接报错“kex_exchange_identification: read: Connection reset by peer”

已经被VScode ssh毒死好几次了&#xff0c;都是执行命令意外中断&#xff0c;然后又VSCode里连不上、本机Terminal也连不上了。。。 重启远程服务器&#xff0c;VSCode可以连上了&#xff0c; 系统ssh还是不行&#xff0c;报错“kex_exchange_identification: read: Connecti…

容器(JAVA基础)

一.泛型 在Java中,泛型(Generics)是JDK 5.0引入的一个新特性,它允许在定义类、接口和方法时使用类型参数(type parameters)。类型参数在使用前必须先被实际类型(如Integer、String等)替代,这个过程称作类型实例化或类型擦除。泛型提供了编译时类型安全,减少了运行时…

CSS~~

CSS是一门语言&#xff0c;用于控制网页表现 CSS(Cascading Style Sheet):层叠样式表 W3C标准:网页主要由三部分组成 结构:HTML 表现: CSS 行为:JavaScript 1&#xff0c;CSS的导入方式 &#xff08;1&#xff09;内联样式 在标签内部使用style属性&#xff0c;属性值是cs…

类 Unix 系统的文件目录结构

以下是类 Unix 系统的文件目录结构、各个目录主要存放的文件以及缩写的全称的详细说明&#xff1a; 根目录 /&#xff1a; 全称: Root Directory说明&#xff1a;根目录是整个文件系统的起点&#xff0c;包含了所有其他目录和文件。 /bin 目录&#xff1a; 全称: Binary说明&a…

Nginx最常用的指令

服务管理 sudo systemctl status nginx # nginx当前状态 sudo systemctl reload nginx # 重新加载 nginx sudo systemctl restart nginx # 重启nginxsudo nginx -t # 检查语法 nginx # 启动 nginx -s reload # 重启 nginx -s stop # 关闭进程 nginx -s quit #…

Java学习笔记002——类的修饰符

在Java语言中&#xff0c;类的访问修饰符决定了其它类能够访问该类的方式。类有如下4种访问修饰符&#xff0c;在创建类时用于类的声明&#xff1a; 1、public: 当一个类被声明为public时&#xff0c;它可以从任何其他类中被访问&#xff0c;无论这些类位于哪个包中。通常&am…

uniapp使用vue3语法构建自定义导航栏,适配小程序胶囊

具体代码 <template><view class"nav-wrapper-container" :style"height:navBarHeight px"><view class"nav-status-container" :style"height:navstatusBarHeight px;" /><view v-if"isCustom" clas…

数字化转型导师坚鹏:BLM证券公司数字化转型战略

BLM证券公司数字化转型战略 ——以BLM模型为核心&#xff0c;实现知行果合一 课程背景&#xff1a; 很多证券公司存在以下问题&#xff1a; 不知道如何系统地制定证券公司数字化转型战略&#xff1f; 不清楚其它证券公司数字化转型战略是如何制定的&#xff1f; 不知道…

Redis 淘汰策略、持久化、高可用

淘汰策略 只有 redis 内存空间已满并且往里面写新数据&#xff0c;才会触发淘汰策略。通过 expire / / /pexpire 让 key-value 过期&#xff0c;从而让 redis 清除这个 key-value。value 的数据结构typedef struct redisObject {unsigned tpye:4;unsigned encoding:4;// 判断哪…

个人数仓开发面试题记录

一.广州电商公司 1.简单自我介绍 2.介绍下之前的公司离线数仓项目 3.mysql和hive区别&#xff1f; 4.sql的执行顺序&#xff1f; 5.hive的优化 6.说下你之前公司来&#xff0c;你的技能层次在每个公司&#xff1f;你怎么评价你的技能&#xff1f; 7.你的之前业务主要是做什么&…

Linux基础命令[10]-cmp

文章目录 1. cmp 命令说明2. cmp 命令语法3. cmp 命令示例3.1 不加参数3.2 -b&#xff08;显示不同的字节&#xff09;3.3 -i&#xff08;跳过字节&#xff09;3.4 -l&#xff08;显示所有不同&#xff09;3.5 -n&#xff08;比较n个字节&#xff09;3.6 -s&#xff08;不显示信…

el-select 不能重复选择

el-select 不能重复选择&#xff0c;注意&#xff1a;删除后可以再次重新被选择 <el-form-item><el-select v-model"attribute.attributeSelect" change"changeSelect()" placeholder"请选择属性分组" clearable><el-optionv-fo…