python-leetcode 33.排序链表
题目:
给定链表的头结点head,请将其按升序排列,并返回排序后的链表

方法一:自顶向下归并排序
链表自顶向下归并排序的过程:
1.找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点
2.对两个链表进行排序
3.将两个排序后的子链表合并,得到完整的排序后的链表。可以使用[合并两个有序链表]的做法,将两个有序的子链表进行合并
可以通过递归实现。递归的终止条件是链表的节点个数小于或等于 1,即当链表为空或者链表只包含 1 个节点时,不需要对链表进行拆分和排序

# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):def sortList(self, head):""":type head: Optional[ListNode]:rtype: Optional[ListNode]"""def sortFunc(head,tail):#个递归的排序函数,tail 是递归调用时用于控制链表的尾部的边界if not head: #链表已经空return headif head.next==tail: #当前链表只有一个元素,或者已经到达分割链表的边界head.next=Nonereturn headslow=fast=headwhile fast !=tail:slow=slow.nextfast=fast.nextif fast != tail: #fast 每次走两步,slow 每次走一步fast=fast.nextmid=slow #当 fast 到达链表尾部时,slow 就在链表的中间位置return merge(sortFunc(head,mid),sortFunc(mid,tail))
#递归调用sortFunc对head到mid的部分和mid到tail的部分分别进行排序,然后将两个排序好的部分合并。合并的过程交给 merge 函数def merge(head1,head2): #将两个已排序的链表合并成一个有序的链表dummyHead=ListNode(0) #虚拟的头节点temp,temp1,temp2=dummyHead,head1,head2
#临时指针,用来构建最终合并的链表,两个已排序链表的头节点while temp1 and temp2: #同时遍历temp1和temp2,比较它们的值,并将较小的节点连接到 temp 上,直到其中一个链表遍历完if temp1.val<temp2.val:temp.next=temp1 #将 temp1 加入合并后的链表temp1=temp1.next #将 temp1 移动到下一个节点else:temp.next=temp2temp2=temp2.nexttemp=temp.next #将已合并链表的指针后移if temp1: #如果 temp1 链表剩余节点未合并完,则直接将剩余的节点连接temp.next=temp1elif temp2: #如果 temp2 链表剩余节点未合并完,同样将剩余的节点连接到temp.next=temp2return dummyHead.next #去除虚拟结点,返回合并后的链表的头节点return sortFunc(head,None) #sortList 函数通过调用 sortFunc 来对整个链表进行排序,None 作为 tail 的参数表示没有上限
时间复杂度:O(nlogn)
空间复杂度:O(nlogn)
方法二:自底向上归并排序
首先求得链表的长度 length,然后将链表拆分成子链表进行合并。
具体做法:
-
用 subLength 表示每次需要排序的子链表的长度,初始时 subLength=1。
-
每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength)按照每两个子链表一组进行合并,合并后即可得到若干个长度为subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。合并两个子链表仍然使用[合并两个有序链表]的做法。
-
将 subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。
举例:
首先,归并长度为 1 的子链表。例如 [4,2,1,3],把第一个节点和第二个节点归并,第三个节点和第四个节点归并,得到 [2,4,1,3]。
然后,归并长度为 2 的子链表。例如 [2,4,1,3],把前两个节点和后两个节点归并,得到 [1,2,3,4]。
然后,归并长度为 4 的子链表。
依此类推,直到归并的长度大于等于链表长度为止,此时链表已经是有序的了。
初始链表: 4 -> 2 -> 1 -> 3
step = 1:
- 分割: [4], [2], [1], [3]
- 合并: [2 -> 4], [1 -> 3]
- 结果: 2 -> 4 -> 1 -> 3
step = 2:
- 分割: [2 -> 4], [1 -> 3]
- 合并: [1 -> 2 -> 3 -> 4]
- 结果: 1 -> 2 -> 3 -> 4
step = 4:
- 分割: [1 -> 2 -> 3 -> 4]
- 无需合并
- 结果: 1 -> 2 -> 3 -> 4
最终结果: 1 -> 2 -> 3 -> 4
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = nextclass Solution(object):# 获取链表长度def getListLength(self, head):length = 0while head:length += 1head = head.nextreturn length# 分割链表# 如果链表长度 <= size,不做任何操作,返回空节点# 如果链表长度 > size,把链表的前 size 个节点分割出来(断开连接),并返回剩余链表的头节点def splitList(self, head, size):# 先找到 next_head 的前一个节点cur = headfor _ in range(size - 1):if cur is None:breakcur = cur.next# 如果链表长度 <= sizeif cur is None or cur.next is None:return None # 不做任何操作,返回空节点next_head = cur.nextcur.next = None # 断开 next_head 的前一个节点和 next_head 的连接return next_head# 合并两个有序链表(双指针)# 返回合并后的链表的头节点和尾节点def mergeTwoLists(self, list1, list2):cur = dummy = ListNode() # 用哨兵节点简化代码逻辑while list1 and list2:if list1.val < list2.val:cur.next = list1 # 把 list1 加到新链表中list1 = list1.nextelse: # 注:相等的情况加哪个节点都是可以的cur.next = list2 # 把 list2 加到新链表中list2 = list2.nextcur = cur.nextif list1:cur.next=list1elif list2:cur.next=list2while cur.next:cur=cur.nextreturn dummy.next, curdef sortList(self, head):length = self.getListLength(head) # 获取链表长度dummy = ListNode(next=head) # 用哨兵节点简化代码逻辑step = 1 # 步长(参与合并的链表长度)while step < length:new_list_tail = dummy # 新链表的末尾cur = dummy.next # 每轮循环的起始节点while cur:# 从 cur 开始,分割出两段长为 step 的链表,头节点分别为 head1 和 head2head1 = curhead2 = self.splitList(head1, step)cur = self.splitList(head2, step) # 下一轮循环的起始节点# 合并两段长为 step 的链表head, tail = self.mergeTwoLists(head1, head2)# 合并后的头节点 head,插到 new_list_tail 的后面new_list_tail.next = headnew_list_tail = tail # tail 现在是新链表的末尾step *= 2return dummy.next
时间复杂度:O(logn)
空间复杂度:O(1)
方法一的归并是自顶向下计算,需要 O(logn) 的递归栈开销。
方法二将其改成自底向上计算,空间复杂度优化成 O(1)
源自力扣官方题解,灵茶山艾府
相关文章:
python-leetcode 33.排序链表
题目: 给定链表的头结点head,请将其按升序排列,并返回排序后的链表 方法一:自顶向下归并排序 链表自顶向下归并排序的过程: 1.找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以…...
【数据结构初阶第十二节】设计循环队列
云边有个稻草人-CSDN博客 必须有为成功付出代价的决心,然后想办法付出这个代价。 还有最后一道关于队列的习题,这题有点难,准备好迎接挑战吧! 目录 1.【题目】 2.实现循环队列推荐用数组,Why? 3.Q1:如…...
基于微信小程序的民宿短租系统设计与实现(ssm论文源码调试讲解)
第4章 系统设计 4.1系统设计的目标 系统设计的目标是满足用户的需求和满足系统实现所需要的所有要求。本系统收集了信息浏览、信息删除、信息添加、信息修改、信息查询为一体[17]。改变了用户民宿短租的方式,提高管理员管理效率以及用户预订的效率。为用户、房主提…...
使用 Jetty 构建 HTTPS 服务入门指南
在互联网安全越来越重要的今天,使用 HTTPS 为 Web 服务提供安全传输成为标准配置。Jetty 是一个高性能、易用且功能丰富的开源 Java HTTP 服务器和 Servlet 容器,能够轻松实现 HTTPS 支持。本文将结合代码实例,引导您快速搭建一个基于 Jetty 的 HTTPS 服务。 一、Jetty 简介…...
数据结构《图》
数据结构《图论》 图的性质 一、无向图(Undirected Graph) 定义 由一组顶点(Vertex)和一组无向边(Edge)构成。 每条无向边用一条无方向的线段连接两个顶点,记为 ( (u, v) ),其中…...
用Chrome Recorder轻松完成自动化测试脚本录制
前言 入门自动化测试,录制回放通常是小白测试首先用到的功能。而录制回放工具也一直是各大Web自动化测试必然会着重提供的一块功能。 早期WinRunner、QTP这样的工具,自动化测试可以说是围绕录制回放开展的。近年像Selenium也提供有录制工具 Selenium IDE,Playwright也包含…...
⭐️苹果电脑安装windows10双系统【详细图文步骤保姆级教程】【本教材适用于MAC台式机、笔记本MacBook air和pro】
苹果电脑安装windows10双系统【详细图文步骤保姆级教程】【本教材适用于MAC台式机、笔记本MacBook air和pro】 苹果电脑安装windows10双系统一、准备工作准备项1:U盘作为系统安装盘准备项2:您需要安装的系统镜像 二、启动转换助理步骤1:找到启…...
win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统
目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 win10系统上的虚拟机安装麒麟V10系统提示找不到操作系统,报错:Operating System not found 二、原因分析 国产系统,需要注意的点: 需要看你的系统类…...
Java 大视界 -- 开源社区对 Java 大数据发展的推动与贡献(91)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
深入浅出C语言内存模型——高阶篇
在C语言编程的征途上,内存管理无疑是最具挑战性的部分之一。今天,我们将深入探讨C语言的内存模型,剖析其高级特性,并通过一系列案例,助你成为内存管理的佼佼者。本文为高阶篇,适合已经有一定C语言基础的读者…...
AI 百炼成神:逻辑回归, 垃圾邮件分类
第二个项目:逻辑回归垃圾邮件分类 项目代码下载地址:https://download.csdn.net/download/m0_56366541/90398247 项目目标 学习逻辑回归的基本概念。使用逻辑回归算法来实现垃圾邮件的分类。理解如何处理文本数据以及如何评估分类模型的性能。项目步骤 准备数据集 我们将使…...
MybatisPlus-扩展功能
逻辑删除乐观锁 MyBatisPlus从入门到精通-3(含mp代码生成器) Db静态工具类 Spring依赖循环问题 代码生成器 MybatisPlus代码生成器 枚举处理器 我们这里用int来存储状态 需要注解,很不灵活 希望用枚举类来代替这个Integer 这样的话我…...
《计算机视觉》——角点检测和特征提取sift
角点检测 角点的定义: 从直观上理解,角点是图像中两条或多条边缘的交点,在图像中表现为局部区域内的灰度变化较为剧烈的点。在数学和计算机视觉中,角点可以被定义为在两个或多个方向上具有显著变化的点。比如在一幅建筑物的图像…...
DeepSeek模型快速部署教程-搭建自己的DeepSeek
前言:在人工智能技术飞速发展的今天,深度学习模型已成为推动各行各业智能化转型的核心驱动力。DeepSeek 作为一款领先的 AI 模型,凭借其高效的性能和灵活的部署方式,受到了广泛关注。无论是自然语言处理、图像识别,还是…...
Swift CChar元祖转String
iOS有些API是调用C函数,Swift端获得的数据是CChar元祖,需要转成String方便使用,下面的代码以获取手机型号为例 方式一 var systemInfo utsname() uname(&systemInfo) let deviceModel withUnsafePointer(to: systemInfo.machine) { …...
【刷题】leetcode
题目 现有 s e r v e r N u m 台服务器,编号依次为 1 − s e r v e r...
WPF创建自定义类和控件及打包成dll引用
WPF创建自定义类和控件及打包成dll引用 一、前言二、创建自定义类和控件并生成dll文件2.1创建类库项目2.2创建自定义类和控件2.3生成dll文件 三、在其他项目中引用3.1添加dll文件引用3.2cs文件中引用命名空间3.3XAML文件中引用命名空间 一、前言 出于一些代码复用的需求&#…...
Zookeeper(54)如何使用Zookeeper的命令行工具?
使用 Zookeeper 的命令行工具可以方便地进行各种操作,如管理节点、查看状态、设置配置信息等。以下是详细的步骤和代码示例,涵盖如何使用 Zookeeper 的命令行工具。 1. 安装和配置 Zookeeper 首先确保已经安装并配置好 Zookeeper。可以在 Zookeeper 的…...
一周学会Flask3 Python Web开发-http响应状态码
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 在Flask程序中,客户端发出的请求触发相应的视图函数,获取返回值会作为响应的主体,最后生成…...
【数据挖掘】
数据挖掘 目录:1. 数据转换2. 属性选择3. 独立于方案的选择4. 探索空间5. 具体方案的选择6. 离散化数值属性无监督离散化基于熵的离散化其他离散化方法 k-means算法原理算法步骤优缺点优点缺点 代码示例(使用Python和scikit-learn库)代码解释…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
