【链表-9】148.排序链表

发布时间:2026/10/16 6:21:34

【链表-9】148.排序链表 题目描述给你链表的头结点head请将其按升序排列并返回排序后的链表。示例 1输入head [4,2,1,3]输出[1,2,3,4]示例 2输入head [-1,5,3,4,0]输出[-1,0,3,4,5]示例 3输入head []输出[]解题思路方法一辅助数组法我的思路先把链表的值存入 vector排序再重建链表。具体步骤边界处理空链表直接返回取值遍历链表把所有值存入temp排序用sort对temp排序重建用排序后的值新建链表节点连接成新链表返回返回新链表头节点用例子走一遍head 4 - 2 - 1 - 3步骤操作结果1遍历链表temp [4, 2, 1, 3]2排序temp [1, 2, 3, 4]3重建链表1 - 2 - 3 - 44返回1 - 2 - 3 - 4✅复杂度分析维度复杂度说明时间复杂度O(n log n)遍历 O(n) 排序 O(n log n) 重建 O(n)空间复杂度O(n)vector 存储 n 个值 新建 n 个节点时间复杂度已经是最优的排序下界就是 O(n log n)但空间复杂度不是最优。缺点❌空间复杂度 O(n)需要额外存储所有值和新建所有节点❌没有利用链表的特性链表题应该用指针操作而不是转成数组和最优解法的对比对比维度方法一最优解法归并排序时间复杂度O(n log n)O(n log n)空间复杂度O(n)O(log n)递归栈或 O(1)迭代是否新建节点✅ 需要❌ 不需要是否修改原链表❌ 不修改✅ 修改面试推荐度⭐⭐⭐⭐⭐⭐⭐⭐方法二归并排序最优解法为什么用归并排序排序算法数组链表快速排序✅ 常用❌ 需要随机访问归并排序✅ 常用✅最适合链表堆排序✅ 常用❌ 需要随机访问归并排序最适合链表因为链表不支持随机访问快排需要随机访问归并排序只需要顺序访问合并两个有序链表是 O(1) 空间操作核心思路1. 快慢指针找中点把链表分成两半 2. 递归排序左半部分 3. 递归排序右半部分 4. 合并两个有序链表代码实现class Solution { public: ListNode* sortList(ListNode* head) { if (head nullptr || head-next nullptr) return head; // 第1步快慢指针找中点 ListNode *slow head, *fast head-next; while (fast ! nullptr fast-next ! nullptr) { slow slow-next; fast fast-next-next; } ListNode *mid slow-next; slow-next nullptr; // 断开链表 // 第2步递归排序左右两半 ListNode *left sortList(head); ListNode *right sortList(mid); // 第3步合并两个有序链表 return merge(left, right); } private: ListNode* merge(ListNode* l1, ListNode* l2) { ListNode *dummy new ListNode(0); ListNode *curr dummy; while (l1 ! nullptr l2 ! nullptr) { if (l1-val l2-val) { curr-next l1; l1 l1-next; } else { curr-next l2; l2 l2-next; } curr curr-next; } curr-next (l1 ! nullptr) ? l1 : l2; return dummy-next; } };复杂度分析维度复杂度时间复杂度O(n log n)空间复杂度O(log n)递归栈深度方法三自底向上归并排序O(1) 空间class Solution { public: ListNode* sortList(ListNode* head) { if (head nullptr || head-next nullptr) return head; // 求链表长度 int len 0; ListNode* p head; while (p ! nullptr) { len; p p-next; } ListNode* dummy new ListNode(0); dummy-next head; // 自底向上归并 for (int size 1; size len; size * 2) { ListNode *prev dummy, *curr dummy-next; while (curr ! nullptr) { ListNode *left curr; ListNode *right split(left, size); curr split(right, size); prev merge(left, right, prev); } } return dummy-next; } private: // 从 head 开始切下 size 个节点返回剩余部分的头 ListNode* split(ListNode* head, int size) { if (head nullptr) return nullptr; for (int i 1; i size head-next ! nullptr; i) { head head-next; } ListNode* rest head-next; head-next nullptr; return rest; } // 合并两个有序链表接到 prev 后面 ListNode* merge(ListNode* l1, ListNode* l2, ListNode* prev) { ListNode* curr prev; while (l1 ! nullptr l2 ! nullptr) { if (l1-val l2-val) { curr-next l1; l1 l1-next; } else { curr-next l2; l2 l2-next; } curr curr-next; } curr-next (l1 ! nullptr) ? l1 : l2; while (curr-next ! nullptr) { curr curr-next; } return curr; } };复杂度时间 O(n log n)空间O(1)三种方法对比方法时间复杂度空间复杂度是否新建节点推荐度辅助数组法O(n log n)O(n)✅ 需要⭐⭐⭐归并排序递归O(n log n)O(log n)❌ 不需要⭐⭐⭐⭐⭐归并排序迭代O(n log n)O(1)❌ 不需要⭐⭐⭐⭐
延伸阅读

更多相关文章

2026/10/16 6:21:34

【链表-8】146.LRU缓存

题目描述: 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值&am…

2026/10/16 6:16:34

2S锂电池主动均衡实战:基于MP2642与STM32的双向能量转移方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 7:42:01

基于Vue+SpringBoot+Node.js的评奖评优管理系统全栈实践

这不是我第一次做高校业务系统,但每次遇到“评奖评优”这类流程型需求,还是会格外谨慎。原因很简单:表面上它只是“学生提交申请、老师审核、名单公示”三步,实际上背后牵涉多角色协作、材料完整性、量化打分、状态变更留痕、批次…

2026/10/16 7:42:01

外卖点评系统核心设计:维度拆解、评分聚合与异常识别

1. 系统设计与需求拆解1.1 外卖点评和到店点评的本质差异说到点评系统,很多人第一反应是照搬到店评价那一套:打分、写文字、传图片。但真正在外卖场景里跑过一遍就会明白,两者面对的完全是两种信任模型。到店评价建立在“我亲眼看到了环境、摸…

2026/10/16 7:42:01

Python文件读取:read()、readline()、readlines()的区别与选型

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 7:42:01

Flink Exactly Once 实现原理与生产落地四大关键

1. 为什么“Exactly Once”不是一句口号,而是Flink工程落地的生死线在某次跨部门数据对账会上,A同学指着大屏上实时订单金额与T1离线报表的3.7%偏差,语气平静但问题尖锐:“上游说Flink保证Exactly Once,下游说Kafka消费…

2026/10/16 7:37:00

考研408应用层协议高频考点与复习方法全解析

1. 应用层到底在考什么:先搞清楚这章的分值分布很多人复习到应用层就开始飘了,觉得前面传输层、网络层那么难都啃下来了,应用层不就是几个协议背一背的事吗。我当年第一次做真题也是这个心态,结果选择题连着错三道,大题…

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/16 0:01:11

Cephadm实战指南:Linux系统工程师的生产级Ceph集群部署与排障

简介:本资源是一份完整的Ceph分布式存储系统中文技术文档合集,面向Linux系统运维工程师、云平台架构师及存储方向开发者,帮助读者系统掌握Ceph集群的部署、配置与运维核心能力。文档覆盖对象存储(RGW)、块设备&#xf…

2026/10/16 0:01:11

ITK中SpatialObject几何体系解析:坐标系、变换与管道集成

1. 空间对象的定位:为什么 ITK 需要一套几何描述体系很多刚开始接触 ITK 的朋友,包括我自己,最初都是被它的图像滤波、配准、分割这些“正统”功能吸引进来的。等真正上手做点实际项目,比如把分割出来的器官边界做量化分析、给血管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑