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

文章目录

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

题目

标题和出处

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

出处: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.rhkb.cn/news/269032.html

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

相关文章

力扣 第 125 场双周赛 解题报告 | 珂学家 | 树形DP + 组合数学

前言 整体评价 T4感觉有简单的方法&#xff0c;无奈树形DP一条路上走到黑了&#xff0c;这场还是有难度的。 T1. 超过阈值的最少操作数 I 思路: 模拟 class Solution {public int minOperations(int[] nums, int k) {return (int)Arrays.stream(nums).filter(x -> x <…

springboot230基于Spring Boot在线远程考试系统的设计与实现

在线远程考试系统设计与实现 摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到…

协议和序列化反序列化

“协议”和序列化反序列化 “协议”的概念&#xff1a; “协议”本身是一种约定俗成的东西&#xff0c;由通讯双方必须共同遵从的一组约定&#xff0c;因此我们一定要将这种约定用计算机语言表达出来&#xff0c;此时双方计算机才能识别约定的相关内容 我们把这个规矩叫做“…

今晚打老虎:用katalon解决接口/自动化测试拦路虎--参数化

不管是做接口测试还是做自动化测试&#xff0c;参数化肯定是一个绕不过去的坎。 因为我们要考虑到多个接口都使用相同参数的问题。所以&#xff0c;本文将讲述一下katalon是如何进行参数化的。 全局变量 右侧菜单栏中打开profile&#xff0c;点击default&#xff0c;打开之后…

【LeetCode】升级打怪之路 Day 11:栈的应用、单调栈

今日题目&#xff1a; Problem 1: 栈的应用 155. 最小栈 | LeetCode20. 有效的括号 | LeetCode150. 逆波兰表达式求值 | LeetCode Problem 2: 单调栈 496. 下一个更大元素 I739. 每日温度503. 下一个更大元素 II 目录 Problem 1&#xff1a;栈 - “先进后出”的应用LC 155. 最…

IO(Linux)

文件系统 前言1. 回顾关于C文件部分函数2. 一些文件知识的共识3. 相对路径4. fwrite中的\0 一、文件描述符fd1. 概念2. 系统调用① open 和 close② write③ read 和 lseek 3. 缺省打开的fd 二、重定向1. 原理2. 系统调用dup23. stdout和stderr的区别4. 进程替换和原来进程文件…

Linux笔记-3

软件安装 概述 在Linux中&#xff0c;软件安装分为3种方式&#xff1a;绿色安装(压缩包解压之后就能直接使用)&#xff0c;rpm安装(类似于Windows中的exe或者msi文件)&#xff0c;yum安装 RPM(Red Hat Package Manager)&#xff1a;红帽提供的软件包的管理工具。可以通过rpm命…

Github项目推荐-LightMirrors

项目地址 https://github.com/NoCLin/LightMirrors 项目简述 “LightMirrors是一个开源的缓存镜像站服务&#xff0c;用于加速软件包下载和镜像拉取。目前支持DockerHub、PyPI、PyTorch、NPM等镜像缓存服务。 当前项目仍处于早期阶段。”–来自项目说明。 也就是说&#xff…

vue中使用prettier

前言&#xff1a;prettier是一款有态度的代码格式化工具&#xff0c;它可以集成在IDE中&#xff0c;如VS Code、Web Storm等&#xff0c;也可以安装到我们开发的项目里面。本文主要讲解在Vue中集成prettier的过程&#xff0c;可以便于代码检测和格式化。 prettier官网 从官网的…

ardupilot 及PX4姿态误差计算算法对比分析

目录 文章目录 目录摘要1.APM姿态误差计算算法2.PX4姿态误差计算算法3.结论摘要 本节主要记录ardupilot 及PX4姿态误差计算算法差异对比过程,欢迎批评指正。 备注: 1.创作不易,有问题急时反馈 2.需要理解四元物理含义、叉乘及点乘含义、方向余弦矩阵含义、四元数乘法物理含…

vue+element ui上传图片到七牛云服务器

本来打算做一个全部都是前端完成的资源上传到七牛云的demo&#xff0c;但是需要获取token&#xff0c;经历了九九八十一难&#xff0c;最终还是选择放弃&#xff0c;token从后端获取&#xff08;springboot&#xff09;。如果你们有前端直接能解决的麻烦记得私我哦&#xff01;…

【最新】如何将idea上的项目推送到gitee

1.打开Gitee&#xff0c;在首页&#xff0c;点击“”&#xff0c;创建一个仓库 2.填写仓库基本信息 3.下拉&#xff0c;点击“创建”&#xff0c;出现下方页面&#xff0c;证明仓库创建成功。 4.打开idea&#xff0c;下载gitee的插件&#xff08;此处默认已经下载git&#xff0…

布隆过滤器实战

一、背景 本篇文章以解决实际需求的问题的角度进行切入&#xff0c;探讨了如果使用布隆过滤器快速丢弃无效请求&#xff0c;降低了系统的负载以及不必要的流量。 我们都知道布隆过滤器是以占用内存小&#xff0c;同时也能够实现快速的过滤从而满足我们的需求&#xff0c;本篇…

termux上安装Python

Termux是一款Android平台下的终端模拟器和Linux环境应用&#xff0c;它允许用户在移动设备上访问Linux命令行界面&#xff0c;以便使用命令行工具、脚本、开发环境等功能。 要在Termux上安装Python&#xff0c;请按照以下步骤进行操作&#xff1a; 一&#xff0c;下载termux …

温湿度传感器SHT21

SHT21是一款基于IIC的温湿度传感器&#xff0c;它的引脚及定义如下&#xff1a; 标准的IIC器件&#xff0c;没有其他多余的引脚&#xff0c;应用框图如下&#xff1a; 温度的测量范围是-40到125℃&#xff0c;湿度测量范围0-100%RH&#xff0c;具体参数及采样精度见下图&#x…

如何限制一个账号只在一处登陆

大家好&#xff0c;我是广漂程序员DevinRock&#xff01; 1. 需求分析 前阵子&#xff0c;和问答群里一个前端朋友&#xff0c;随便唠了唠。期间他问了我一个问题&#xff0c;让我印象深刻。 他问的是&#xff0c;限制同一账号只能在一处设备上登录&#xff0c;是如何实现的…

C语言操作符详解(一)

一、操作符的分类 • 算术操作符&#xff1a; 、- 、* 、/ 、% • 移位操作符:<< >> • 位操作符: & | ^ • 赋值操作符: 、 、 - 、 * 、 / 、% 、<< 、>> 、& 、| 、^ • 单⽬操作符&#xff1a; &#xff01;、、--、&、*、、…

嵌入式基础知识-信号量,PV原语与前趋图

本篇来介绍信号量与PV原语的一些知识&#xff0c;并介绍其在前趋图上的应用分析。本篇的知识属于操作系统部分的通用知识&#xff0c;在嵌入式软件开发中&#xff0c;同样会用到这些知识。 1 信号量 信号量是最早出现的用来解决进程同步与互斥问题的机制&#xff08;可以把信…

深入了解 Android 中的 FrameLayout 布局

FrameLayout 是 Android 中常用的布局之一&#xff0c;它允许子视图堆叠在一起&#xff0c;可以在不同位置放置子视图。在这篇博客中&#xff0c;我们将详细介绍 FrameLayout 的属性及其作用。 <FrameLayout xmlns:android"http://schemas.android.com/apk/res/androi…

计算机组成原理(超详解!!) 第一节 导论

1.计算机的性能指标 1.字长 一般大型计算机字长为32位或64位&#xff1b; 小型计算机字长为16位或32位&#xff1b;微型计算机字长有1位、4位、8位、16位&#xff1b; 高档微型计算机字长为32位和64位。对于字长短的计算机&#xff0c;为了提高计算精度&#xff0c;采用多字…