在问 · 算法题解

147. 对链表进行插入排序

题目描述

输入单链表的头节点 head。用插入排序把链表按节点值从小到大排列,返回排序后的头节点。

插入排序的做法:维护一个已排好序的部分,初始只含第一个节点。每轮从剩余部分取出一个节点,在已排好的部分中找到它应在的位置并插进去。所有节点都插完后排序结束。

链表用数组表示,例如 [1,2,3]。

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

解释:依次插入 2、1、3 后得到 [1,2,3,4]。

示例 2
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

解释:排序后为 [-1,0,3,4,5]。

数据范围

  • 节点数在 [1, 5000] 之间。
  • -5000 <= Node.val <= 5000

解题思路

用一个哑节点 dummy 挂一条“已排序链表”,开始为空。每次从原链表摘下一个节点 cur:先用 nxt 记住它的后继,再让 prev 从 dummy 出发向后走,停在第一个“下一个值不小于 cur.val”的位置,把 cur 接到 prev 后面。哑节点让“插到最前面”和“插到中间”写法完全一样。

为什么正确

每轮开始时,dummy.next 起的链是已处理节点的升序排列;nxt 起的链是尚未处理的原始顺序。

复杂度分析

时间 O(n^2)(每次插入最多扫描整条已排序链),额外空间 O(1)。

易错点

改 cur.next 之前必须先保存 nxt = cur.next,否则剩下的原链表就丢了。比较要用 prev.next.val < cur.val(看下一个),而不是 prev.val。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        dummy = ListNode(0)
        cur = head
        while cur:
            nxt = cur.next
            prev = dummy
            while prev.next and prev.next.val < cur.val:
                prev = prev.next
            cur.next = prev.next
            prev.next = cur
            cur = nxt
        return dummy.next

载入编辑器,自己跑一遍 →

链表 专题的其他题目

查看 链表 全部题目 →