全栈开发知识库

66.分隔链表

题目

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

示例 1:

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

说明:小于 3 的节点是 1、2、2(按原顺序);大于等于 3 的是 4、3、5(按原顺序); 把前者拼在后者前面。

示例 2:

  • 输入:head = [2,1], x = 2
  • 输出:[1,2]

提示:

  • 链表中节点的数目在范围 [0, 200] 内
  • -100 <= Node.val <= 100
  • -200 <= x <= 200

思路

分成两队,最后合并

这道题的思路特别直白,就像排队分流:

想象成一个门口有个安检,你手里拿着标准值x。链表里的节点排着队一个一个过来:

  • 值小于x的节点,让它排到小队里。
  • 值大于等于x的节点,让它排到大队里。

因为我们是按照原链表顺序依次处理每个节点的,所以每个分区内部自然就保持了原来的相对顺序(先来的先排,后来的后排)。

最后,把小队的尾巴接上大队的头,两队拼成一条链,就是答案。

原链表: 1 -> 4 -> 3 -> 2 -> 5 -> 2 x = 3

分流:

  • 小队(<3): 1 -> 2 -> 2
  • 大队(>=3): 4 -> 3 -> 5
  • 合并: 1 -> 2 -> 2 -> 4 -> 3 -> 5

两个dummy: 给两条新链各配一个头

我们要新建两条链表(小队和大队),但一开始它们都是空的,没有头节点,往里加节点时会很麻烦(需要判断是不是第一个节点)。

老办法: 给每条链都配一个dummy哨兵节点:

  • smallDummy: 小队的虚拟头,配一个移动指针samll负责往小队尾部接节点
  • largeDummy: 大队的虚拟头,配一个移动指针large负责往大队尾部接节点

class ListNode(var `val`: Int) {
    var next: ListNode? = null
}

class Solution {
    fun partition(head: ListNode?, x: Int): ListNode? {
        // 1. 两个哨兵节点,分别作为"小队"和"大队"的虚拟头
        val smallDummy = ListNode(0)
        val largeDummy = ListNode(0)

        // small / large 是两条链的尾指针,负责往各自队尾追加节点
        var small: ListNode = smallDummy
        var large: ListNode = largeDummy

        // 2. 遍历原链表,把每个节点按值分流到两条链中
        var cur = head
        while (cur != null) {
            if (cur.`val` < x) {
                small.next = cur       // 接到小队尾部
                small = cur            // 更新小队尾指针
            } else {
                large.next = cur       // 接到大队尾部
                large = cur            // 更新大队尾指针
            }
            cur = cur.next
        }

        // 3. 收尾一:大队尾部置空,切断原链表残留的指向,防止成环
        large.next = null

        // 4. 收尾二:小队尾部接上大队的头,拼成完整链表
        small.next = largeDummy.next

        // 5. 返回小队的真正头节点
        return smallDummy.next
    }
}

复杂度

  • 时间复杂度: O(n):只遍历一遍原链表,每个节点处理一次。
  • 空间复杂度: O(1):只用了两个 dummy 和几个指针,没有开辟和节点数成正比的额外空间(节点是复用原链表的,没有新建)。


  • 邮箱 :charon.chui@gmail.com
  • Good Luck!
本页由 Markdown 自动渲染 · 共 628 篇笔记