二叉搜索树题目:将有序链表转换为二叉搜索树

文章目录

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

题目

标题和出处

标题:将有序链表转换为二叉搜索树

出处:109. 将有序链表转换为二叉搜索树

难度

5 级

题目描述

要求

给定单链表的头结点 head \texttt{head} head,其中元素已经按升序排列,将其转换为高度平衡二叉搜索树。

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

示例

示例 1:

示例 1

输入: head = [-10,-3,0,5,9] \texttt{head = [-10,-3,0,5,9]} head = [-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,-3,9,-10,null,5] \texttt{[0,-3,9,-10,null,5]} [0,-3,9,-10,null,5],表示如图所示的高度平衡二叉搜索树。

示例 2:

输入: head = [] \texttt{head = []} head = []
输出: [] \texttt{[]} []

数据范围

  • 链表 head \texttt{head} head 中结点数目在范围 [0, 2 × 10 4 ] \texttt{[0, 2} \times \texttt{10}^\texttt{4}\texttt{]} [0, 2×104]
  • -10 5 ≤ Node.val ≤ 10 5 \texttt{-10}^\texttt{5} \le \texttt{Node.val} \le \texttt{10}^\texttt{5} -105Node.val105

前言

这道题和「将有序数组转换为二叉搜索树」相似,区别在于这道题给定有序链表。

为了得到高度平衡二叉搜索树,构造的二叉搜索树应满足根结点的左子树和右子树的结点数尽可能接近,左子树和右子树也都是高度平衡二叉搜索树。

解法一

思路和算法

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

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

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

由于高度平衡二叉搜索树的每个子树也都是高度平衡二叉搜索树,每个子树包含的结点值的集合对应给定的链表中的连续子链表,因此可以使用递归分治的方式构造高度平衡二叉搜索树,递归的过程中只要指定每个子树包含的结点值的集合对应的连续子链表的区间 [ start , end ) [\textit{start}, \textit{end}) [start,end) 即可,该区间是左闭右开区间,区间包含 start \textit{start} start,不包含 end \textit{end} end

递归的终止条件是区间为空,即 start = end \textit{start} = \textit{end} start=end,此时对应的子树为空。对于其余情况,首先根据 start \textit{start} start end \textit{end} end 定位到子链表区间的中间结点并使用中间结点值创建根结点,然后分别使用中间结点左边和右边的两个区间创建根结点的左子树和右子树。定位到子链表区间的中间结点可以通过快慢指针实现。

start ≠ end \textit{start} \ne \textit{end} start=end 时,中间结点的唯一性取决于区间 [ start , end ) [\textit{start}, \textit{end}) [start,end) 内的元素个数的奇偶性。如果区间 [ start , end ) [\textit{start}, \textit{end}) [start,end) 内的元素个数是奇数,则中间结点是唯一的;如果区间 [ start , end ) [\textit{start}, \textit{end}) [start,end) 内的元素个数是偶数,则中间结点是不唯一的,可以是中间位置左边的结点或者中间位置右边的结点。

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

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

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

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

代码

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

class Solution {public TreeNode sortedListToBST(ListNode head) {return createBST(head, null);}public TreeNode createBST(ListNode start, ListNode end) {if (start == end) {return null;}ListNode slow = start, fast = start.next;while (fast != end && fast.next != end) {slow = slow.next;fast = fast.next.next;}return new TreeNode(slow.val, createBST(start, slow), createBST(slow.next, end));}
}

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

class Solution {public TreeNode sortedListToBST(ListNode head) {return createBST(head, null);}public TreeNode createBST(ListNode start, ListNode end) {if (start == end) {return null;}ListNode slow = start, fast = start;while (fast != end && fast.next != end) {slow = slow.next;fast = fast.next.next;}return new TreeNode(slow.val, createBST(start, slow), createBST(slow.next, end));}
}

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

class Solution {Random random = new Random();public TreeNode sortedListToBST(ListNode head) {return createBST(head, null);}public TreeNode createBST(ListNode start, ListNode end) {if (start == end) {return null;}ListNode slow = start, fast = start.next;while (fast != end && fast.next != end) {slow = slow.next;fast = fast.next.next;}if (fast != end && random.nextBoolean()) {slow = slow.next;}return new TreeNode(slow.val, createBST(start, slow), createBST(slow.next, end));}
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是链表 head \textit{head} head 的长度。用 T ( n ) T(n) T(n) 表示用长度为 n n n 的链表构造高度平衡二叉搜索树的时间,则有 T ( n ) = 2 × T ( n 2 ) + O ( n ) T(n) = 2 \times T\Big(\dfrac{n}{2}\Big) + O(n) T(n)=2×T(2n)+O(n),根据主定理可知 T ( n ) = O ( n log ⁡ n ) T(n) = O(n \log n) T(n)=O(nlogn)

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

解法二

思路和算法

解法一需要多次定位中间结点,因此时间复杂度较高。由于给定的升序链表即为二叉搜索树的中序遍历序列,因此可以在遍历链表的过程中构造高度平衡二叉搜索树。

首先遍历链表得到链表的长度 n n n,则高度平衡二叉搜索树对应的下标区间是 [ 0 , n − 1 ] [0, n - 1] [0,n1]。对于下标区间 [ 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 = ⌊ start + end + 1 2 ⌋ \textit{mid} = \Big\lfloor \dfrac{\textit{start} + \textit{end} + 1}{2} \Big\rfloor mid=2start+end+1,左子树和右子树分别对应下标区间 [ 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}, \textit{end}] [start,end] 内的元素个数是偶数时, mid \textit{mid} mid 的取值不唯一,因此同样存在三种构造高度平衡二叉搜索树的方法。

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

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

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

代码

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

class Solution {ListNode curr;public TreeNode sortedListToBST(ListNode head) {curr = head;int length = 0;ListNode node = head;while (node != null) {length++;node = node.next;}return createBST(0, length - 1);}public TreeNode createBST(int start, int end) {if (start > end) {return null;}int mid = (end - start) / 2 + start;TreeNode left = createBST(start, mid - 1);int rootVal = curr.val;curr = curr.next;TreeNode right = createBST(mid + 1, end);return new TreeNode(rootVal, left, right);}
}

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

class Solution {ListNode curr;public TreeNode sortedListToBST(ListNode head) {curr = head;int length = 0;ListNode node = head;while (node != null) {length++;node = node.next;}return createBST(0, length - 1);}public TreeNode createBST(int start, int end) {if (start > end) {return null;}int mid = (end - start + 1) / 2 + start;TreeNode left = createBST(start, mid - 1);int rootVal = curr.val;curr = curr.next;TreeNode right = createBST(mid + 1, end);return new TreeNode(rootVal, left, right);}
}

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

class Solution {Random random = new Random();ListNode curr;public TreeNode sortedListToBST(ListNode head) {curr = head;int length = 0;ListNode node = head;while (node != null) {length++;node = node.next;}return createBST(0, length - 1);}public TreeNode createBST(int start, int end) {if (start > end) {return null;}int mid = (end - start + random.nextInt(2)) / 2 + start;TreeNode left = createBST(start, mid - 1);int rootVal = curr.val;curr = curr.next;TreeNode right = createBST(mid + 1, end);return new TreeNode(rootVal, left, right);}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表 head \textit{head} head 的长度。用 T ( n ) T(n) T(n) 表示用长度为 n n n 的链表构造高度平衡二叉搜索树的时间,则有 T ( n ) = 2 × T ( n 2 ) + O ( 1 ) T(n) = 2 \times T\Big(\dfrac{n}{2}\Big) + O(1) T(n)=2×T(2n)+O(1),根据主定理可知 T ( n ) = O ( n ) T(n) = O(n) T(n)=O(n)

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

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

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

相关文章

SPA单页面有哪些优缺点

单页面应用(SPA)作为一种现代化的Web应用程序架构,在当今互联网时代越来越受到开发者和用户的欢迎。它通过在加载应用程序时只加载一次页面,实现页面内容的动态更新,带来了许多优势和挑战。本文将深入探讨SPA的优点和缺…

【kaggle竞赛】从手写图像数据集中正确识别数字

1. 题目: 在本次比赛中,您的目标是从数以万计的手写图像数据集中正确识别数字。 1.1. Goal 目标✨ 本次比赛的目标是拍摄手写个位数的图像,并确定该数字是什么。 对于测试集中的每个标签,您都应该预测正确的标签。 本次比赛的…

SpringCloudLoadBalancer入门与实战系列

目录 一、什么是LoadBalancer? 1.1 负载均衡的分类 1.2 负载均衡策略 二、 为什么要学习 Spring Cloud Balancer ? 三、 Spring Cloud LoadBalancer 内置的两种负载均衡策略 3.1 轮询负载均衡策略(默认的) 3.2 随机负载均衡…

科研学习|研究方法——案例研究方法

目录 1.案例研究的起源 2.案例研究的说服力 2.1 外界质疑 2.1.1 样本数量太小 2.1.2 选择的样本带有偏倚 2.1.3 选择的案例太少 2.1.4 无法验证 2.2 重要作用 2.2.1 激发研究 2.2.2 启发灵感 2.2.3 提供佐证 3.案例研究的内容 4.案例研究质量的评价 5.案例研究的优缺点 6.MI…

wsl or 虚拟机 安装

1.wsl2安装 WSL全称Windows Subsystem for Linux,是微软开发的适用于Linux的Windows子系统 如今已经有两代了: 所以用的多的还是wsl2。 安装前需要先去设置启用或关闭Windows功能: 打开适用于linux的子系统和虚拟机平台。 Microsoft Store里…

【实验01 扩展实验】C#桌面项目:简易计算器

【实验要求】 (1)新建一个C#桌面项目Calc,实现简易计算器功能,界面如图1所示。 (2)计算方式:通过点击对应的按钮,输入第1个数(可以是整数或实数)&#xff0c…

微服务:高并发带来的问题的容错方案

1.相关脚本(陈天狼) 启动nacos客户端: startup.cmd -m standalone 启动sentinel控制台: # 直接使⽤jar命令启动项⽬(控制台本身是⼀个SpringBoot项⽬) java -Dserver.port8080 -Dcsp.sentinel.dashboard.serverlocalhost:808…

【复现】【免费】基于多时间尺度滚动优化的多能源微网双层调度模型

目录 主要内容 部分代码 结果一览 1.原文结果 2.程序运行结果 下载链接 主要内容 该模型参考《Collaborative Autonomous Optimization of Interconnected Multi-Energy Systems with Two-Stage Transactive Control Framework》,主要解决的是一个…

03|提示工程(下):用思维链和思维树提升模型思考质量

什么是 Chain of Thought CoT这个概念来源于学术界,是谷歌大脑的Jason Wei等人于2022年在论文《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models(自我一致性提升了语言模型中的思维链推理能力)》中提出来的概念。它…

2024-Spring IOC 和 AOP源码分析(上篇)

**前言:**笔者最近面了几次大厂。。。开局Spring源码暴击 之前看过忘了写篇总结。。。 1、介绍一下Spring 核心组件: 常用模块: 常用注解: 2、说一下SpringIOC原理 概念:Spring 通过一个配置文件描述 Bean 及 B…

【Godot4自学手册】第二十六节用GPUParticles2D节点实现地宫入口的奇异光芒

我们的主人公与NPC对话完成后,夜晚来临,在城北有一处乱石岗,出现了奇异光芒,这是地宫的入口,但是有一妖怪把守,我们必须消灭妖怪后才可发现地宫入口。这一节,主要记录利用粒子系统GPUParticles2…

Python和R的区别是什么,Python与R的应用场景是什么?

如果你这么问,那么你可能正站在数据科学的起点。对于志在成为数据专业人员的你来说,学习编程是无疑的。我想行你早就听过Python 与R的比较之声,并在选择中感到困惑。在此,我想说,也算是一种安慰吧:对于语言…

TypeScript:typescript的安装与运行

TypeScript:typescript的安装与运行 1 安装方式 -g全局安装TypeScript: npm install -g typescript2 运行方式 (1)ts编译成js,使用node命令运行js文件 打开vscode,进入ts文件所在目录下并打开终端term…

【算法】多路归并(鱼塘钓鱼)

有 N 个鱼塘排成一排,每个鱼塘中有一定数量的鱼,例如:N5 时,如下表: 鱼塘编号12345第1分钟能钓到的鱼的数量(1..1000)101420169每钓鱼1分钟钓鱼数的减少量(1..100)24653当前鱼塘到下…

静态综合实验

一,1.搭建拓扑结构并启动。 2.根据题意得该图需要14个网段,根据192.168.1.0/24划分子网段,如下: 划分完如图所示: 二、配置IP地址 R1路由器: 1.进入系统视图并改名. 2.接口配置IP地址&#xff1a…

HTML学习:图片格式——超链接

一、图片格式 1.jpg格式 概述:扩展名为.jpg 或.jpeg ,是一种有损的压缩格式(把肉眼不容易观察出来的细节丢弃了)。 主要特点:支持的颜色丰富、占用空间较小、不支持透明背景、不支持动态图。 使用场景:对图片细节没有极高要求的场景,例如:网站的产品…

Nacos学习笔记

Nacos官网 https://github.com/alibaba/nacos/releases https://www.bilibili.com/video/BV1q3411Z79z 1. Nacos介绍 Nacos是Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 在这个…

SAP Business Application Studio(BAS)中开发Fiori App的基础知识

1. SAP Fiori Tools SAP Fiori Tools是一套用于支持SAP Fiori应用开发的工具,包括应用模板、可视化编辑器、代码生成、应用预览和集成测试工具等。这些工具可以帮助开发者更快速、更简单地创建和维护SAP Fiori应用。SAP Fiori Tools 可与SAP的开发环境(…

MPIKGC:大语言模型改进知识图谱补全

MPIKGC:大语言模型改进知识图谱补全 提出背景MPIKGC框架 论文:https://arxiv.org/pdf/2403.01972.pdf 代码:https://github.com/quqxui/MPIKGC 提出背景 知识图谱就像一个大数据库,里面有很多关于不同事物的信息,这…

003——移植鸿蒙

目录 一、顶层Make分析 二、添加一个新的单板 2.1 Kconfig 2.2 Makefile 2.2.1 顶层Makefile 2.2.2 platform下的Makefile 2.2.3 platform下的bsp.mk文件 2.3 编译与调试 2.4 解决链接错误 三、内核启动流程的学习 3.1 韦东山老师总结的启动四步 3.2 启动文件分析…