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

【Day 20】148.排序链表

文章目录

  • 148.排序链表
  • 题目:
  • 思路:
  • 代码实现(Go):

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 = []
输出:[]

提示:

链表中节点的数目在范围 [0, 5 * 10^4] 内
-10^5 <= Node.val <= 10^5


思路:

  1. 递归终止条件

    • 如果链表为空或者只有一个节点,直接返回,因为空链表或单节点链表天然有序。
  2. 找到链表中点并切割

    • 使用快慢指针:

      • slow 每次走 1 步,fast 每次走 2 步。
      • fast 到达尾部时,slow 停在 左半段的尾节点
    • 将链表从中点切开:

      • 这样左半段从 head 开始,右半段从 second 开始,链表被分为两段。
  3. 递归排序左右两段

    • 递归地对左右半段进行排序,直到每段只剩 1 个节点或者为空

    • 递归调用逻辑

    • 对左半段 head -> ... -> slow 再次执行 sortList

      • 如果左半段长度 > 1,就会再次找中点、切割、递归
      • 最终递归到每段只有一个节点,就返回节点。
    • 对右半段 second -> ... 同理。

  • 结果

    • 左右两段分别返回排好序的链表头。
  1. 合并两个有序链表

    • 新建一个 dummy 节点作为合并链表的头部辅助节点。
    • 遍历左右两个链表,逐个比较节点值,把小的节点接到当前链表尾部。
    • 当一个链表耗尽,把另一个链表剩下的节点直接接上。
  2. 返回合并后的链表

    • dummy.Next 指向合并后的有序链表头。

在这里插入图片描述


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

    • 每次分半是 log n 层,合并两段是 O(n),总共 O(n log n)
  • 空间复杂度O(log n)

    • 递归栈的空间,因为链表不需要额外数组。
  • 适合链表的原因

    • 链表不适合快速排序那样的随机访问,但归并排序只需要顺序访问,非常自然。

代码实现(Go):

详细注解:

// package main// import "fmt"// type ListNode struct {
// 	Val  int
// 	Next *ListNode
// }func sortList(head *ListNode) *ListNode {if head == nil || head.Next == nil {return head // 空链表或单节点直接返回}// 1. 使用快慢指针找到链表中点slow, fast := head, head.Nextfor fast != nil && fast.Next != nil {slow = slow.Nextfast = fast.Next.Next}second := slow.Next // 右半段头保存起来使用,接下来要置空slow.Next = nil     // 切断链表,分成左右两段,左半段最后指向 nil// 2. 递归排序左右两段left := sortList(head)    // 第一段开头right := sortList(second) // 第二段开头// 3. 合并两个有序链表dummy := &ListNode{}cur := dummyfor left != nil && right != nil {if left.Val < right.Val {cur.Next = leftleft = left.Next} else {cur.Next = rightright = right.Next}cur = cur.Next}if left != nil {cur.Next = left} else {cur.Next = right}return dummy.Next
}// func main() {
// 	// 构造链表 [4,2,1,3]
// 	head := &ListNode{
// 		Val: 4,
// 		Next: &ListNode{
// 			Val: 2,
// 			Next: &ListNode{
// 				Val: 1,
// 				Next: &ListNode{
// 					Val:  3,
// 					Next: nil,
// 				},
// 			},
// 		},
// 	}// 	sorted := sortList(head)
// 	// 打印排序后的链表
// 	for sorted != nil {
// 		fmt.Print(sorted.Val, " ")
// 		sorted = sorted.Next
// 	}
// 	// 输出: 1 2 3 4
// }

无注释:

package mainimport "fmt"type ListNode struct {Val  intNext *ListNode
}func sortList(head *ListNode) *ListNode {if head == nil || head.Next == nil {return head}slow, fast := head, head.Nextfor fast != nil && fast.Next != nil {slow = slow.Nextfast = fast.Next.Next}second := slow.Nextslow.Next = nilleft := sortList(head)right := sortList(second)dummy := &ListNode{}cur := dummyfor left != nil && right != nil {if left.Val < right.Val {cur.Next = leftleft = left.Next} else {cur.Next = rightright = right.Next}cur = cur.Next}if left != nil {cur.Next = left} else {cur.Next = right}return dummy.Next
}func main() {head := &ListNode{Val: 4,Next: &ListNode{Val: 2,Next: &ListNode{Val: 1,Next: &ListNode{Val:  3,Next: nil,},},},}sorted := sortList(head)for sorted != nil {fmt.Print(sorted.Val, " ")sorted = sorted.Next}
}

http://www.xdnf.cn/news/20212.html

相关文章:

  • Electron 执行python脚本
  • IPV6、广播地址
  • 单片机实现分页显示环形更新的历史数据
  • 算法随笔(一)
  • S32K328上芯片内部RTC的使用和唤醒配置
  • 深度学习篇---MNIST:手写数字数据集
  • 基础排序--冒泡--选择--插入
  • 【算法--链表】25.K个一组翻转链表--通俗讲解
  • Linux初始化配置——RHEL7.9、9.3环境部署
  • 【C语言】 第三课 函数与栈帧机制详解
  • RTP打包与解包全解析:从RFC规范到跨平台轻量级RTSP服务和低延迟RTSP播放器实现
  • Deeplizard深度学习课程(七)—— 神经网络实验
  • 飞算JavaAI全面解析:重塑Java开发流程的智能引擎
  • 商城源码后端性能优化:JVM 参数调优与内存泄漏排查实战
  • List<?>和List<Object>区别
  • 第二阶段WinForm-12:UI控件库
  • 力扣516 代码随想录Day16 第一题
  • 【涂鸦T5】6. lvgl显示光感数值
  • 鸿蒙:AppStorageV2状态管理和数据共享
  • Gmail 数据泄露安全警报以及启示
  • 【Linux】线程概念与控制
  • 代码随想录刷题Day49
  • house (ai)
  • 对话Michael Truell:23岁创立Cursor,与Github Copilot竞争
  • 【C++上岸】C++常见面试题目--算法篇(第十九期)
  • 2025年8月文章一览
  • 深度学习:自定义数据集处理、数据增强与最优模型管理
  • 数据旁路(Data Bypassing)是什么?
  • 安装3DS MAX 2026后,无法运行,提示缺少.net core的解决方案
  • 2025年数学建模国赛C题第二版本超详细解题思路