当前位置: 首页 > news >正文

LeetCode 148 排序链表解析:高效归并排序实现

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

输入:head = [4,2,1,3]
输出:[1,2,3,4]

代码解析

java

class Solution {public ListNode sortList(ListNode head) {// 递归终止条件:链表为空或只有一个节点if (head == null || head.next == null) {return head;}// 1. 获取链表中点ListNode mid = getMid(head);// 2. 分割链表为两部分ListNode rightHead = mid.next;mid.next = null; // 断开左右链表连接// 3. 递归排序左右子链表ListNode left = sortList(head);ListNode right = sortList(rightHead);// 4. 合并两个已排序的子链表return mergeSort(left, right);}// 合并两个有序链表private ListNode mergeSort(ListNode l1, ListNode l2) {ListNode dummyHead = new ListNode(0); // 哑节点简化操作ListNode cur = dummyHead;// 比较节点值,按升序连接while (l1 != null && l2 != null) {if (l1.val < l2.val) {cur.next = l1;l1 = l1.next;} else {cur.next = l2;l2 = l2.next;}cur = cur.next;}// 连接剩余节点cur.next = (l1 != null) ? l1 : l2;return dummyHead.next;}// 使用快慢指针找到链表中点private ListNode getMid(ListNode head) {ListNode fast = head;ListNode slow = head;// 快指针移动两步,慢指针移动一步while (fast.next != null && fast.next.next != null) {slow = slow.next;fast = fast.next.next;}return slow; // 慢指针指向中点(偶数时偏左)}
}

关键步骤详解

  1. 递归终止条件

    • 当链表为空 (head == null) 或只有一个节点 (head.next == null) 时,直接返回,无需排序。

  2. 获取链表中点(getMid

    • 快慢指针法:快指针每次移动两步,慢指针每次移动一步。

    • 当快指针到达末尾时,慢指针指向中点(链表长度为偶数时指向前半部分最后一个节点)。

  3. 分割链表

    • 将链表从中点处断开:mid.next = null

    • 左子链表范围:[head, mid]

    • 右子链表范围:[mid.next, 末尾]

  4. 递归排序子链表

    • 分别对左右子链表递归调用 sortList,直到子链表满足终止条件。

  5. 合并有序链表(mergeSort

    • 创建哑节点 dummyHead 简化链表连接操作。

    • 比较两个链表的当前节点值,将较小者接入新链表。

    • 当一个链表遍历完成后,将另一个链表的剩余部分直接接入。

复杂度分析

  • 时间复杂度:O(n log n)

    • 每次分割链表需 O(n) 时间(通过快慢指针找中点)。

    • 递归深度为 O(log n),每层合并操作总时间复杂度为 O(n)。

  • 空间复杂度:O(log n)

    • 递归调用栈的深度(非递归版本可优化至 O(1))。

为什么选择归并排序?

  1. 链表特性适配

    • 链表节点不支持随机访问(无法高效实现快速排序的分区)。

    • 归并排序的合并操作只需改变指针,无需额外空间(数组归并需 O(n) 空间)。

  2. 稳定性

    • 归并排序是稳定排序,保持相等元素的原始顺序。

总结

该解法利用分治思想,通过递归将链表不断分割、排序再合并,高效实现了 O(n log n) 的排序。快慢指针找中点与哑节点简化合并操作是处理链表问题的经典技巧。归并排序因其稳定性和适配链表结构的特性,成为解决此类问题的首选方案。

http://www.lryc.cn/news/585019.html

相关文章:

  • 基于Springboot+UniApp+Ai实现模拟面试小工具二:后端项目搭建
  • 【数据结构与算法】203.移除链表元素(LeetCode)图文详解
  • doker和网站部署
  • LeetCode--43.字符串相乘
  • Kotlin 常用语法糖完整整理
  • 九联UNT403AS_S905L3SB当贝固件优盘刷机包下载
  • 9、鸿蒙Harmony Next开发:栅格布局 (GridRow/GridCol)
  • AI产品经理面试宝典第7天:核心算法面试题-上
  • 在 Spring Boot 中使用 WebMvcConfigurer
  • AI技术正以前所未有的速度重塑职业生态与行业格局,尤其在自动化测试领域,AI驱动的测试框架通过智能化、低代码化重构传统测试流程。
  • python solr数据导出脚本
  • 分割网络Segformer
  • 界面组件DevExpress WPF中文教程:Grid - 如何检查节点?
  • mongodb 开源同步工具介绍
  • Windows 应用程序的 UI 框架:WPF、WinUI 3 和 UWP的差异区别
  • Django--02模型和管理站点
  • 【三】ObservableCollection 与 List 的区别
  • 【EGSR2025】材质+扩散模型+神经网络相关论文整理随笔(四)
  • (二)OpenCV——边缘增强与检测
  • 大数据在UI前端的应用创新:基于用户反馈的产品迭代优化系统
  • PPT处理控件Aspose.Slides教程:使用 C# 将 PPTX 转换为 EMF
  • 游戏的程序员会不会偷偷改自己账号的数据?
  • TypeScript---class类型
  • 工业通信升级新选择:耐达讯CCLINKIE转Modbus TCP网关
  • 猿人学js逆向比赛第一届第十九题
  • U-Net网络学习笔记(1)
  • 2025亚太中文赛项 B题疾病的预测与大数据分析保姆级教程思路分析
  • 机器学习数据集加载全攻略:从本地到网络
  • 【读代码】开源音乐分离工具Spleeter
  • 深度学习14(循环神经网络)