LeetCode 86. 分隔链表
题目描述
✅ 86. 分隔链表


题意分析
根据给定值
x把链表分成两组:所有值小于x的节点放在前面,所有值大于或等于x的节点放在后面,并返回新的头节点。两组内部都必须保持节点在原链表中的相对顺序,因此这不是对整条链表排序,也不能把每组倒过来。节点值等于
x时属于后组,所有原节点都要恰好保留一次。
解法:双哑节点稳定分区
核心思路
[!blue]
从头到尾扫描原链表,将每个节点追加到它所属组的末尾。扫描顺序就是原顺序,尾插又不会改变已收集节点的顺序,因此两组各自都能自然保持稳定。
为两组各建一个哨兵和尾指针。哨兵只作为连接起点,不参与结果;即使某一组暂时为空,也能统一执行“尾部接当前节点,再移动尾指针”。
当前节点还带着原来的后继连接,不能直接把它当成独立节点使用。每轮先保存
next,再把当前节点的后继置空,然后按< x或>= x追加到对应组。这样两条已收集的链始终独立、末尾为空,未处理部分则始终由保存的next指向,不会丢节点或保留跨组旧连接。扫描结束时,两条链已经分别包含全部小值节点和其余节点。将小链尾部接到大链头部,便满足整体分组要求,同时两组内部顺序不变。若小链为空,它的尾指针仍是哨兵,连接操作也能直接把答案指向大链;原链为空或大链为空同样不需要额外分支。
解题步骤
- 创建两个哨兵
smallDummy、largeDummy,对应尾指针最初指向各自哨兵。- 对当前节点先保存原后继,再将当前后继置空。
- 节点值小于
x时追加到小链末尾,否则追加到大链末尾,并移动相应尾指针。- 使用保存的原后继继续扫描,直至处理完全部节点。
- 把小链尾部接到
largeDummy.next,返回smallDummy.next。
代码实现
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode smallDummy = new ListNode(0);
ListNode largeDummy = new ListNode(0);
ListNode smallTail = smallDummy;
ListNode largeTail = largeDummy;
while (head != null) {
ListNode next = head.next;
// 已保存原后继,先断开旧连接,让两组始终是独立开链。
head.next = null;
if (head.val < x) {
smallTail.next = head;
smallTail = head;
} else {
largeTail.next = head;
largeTail = head;
}
head = next;
}
// 两组按原顺序收集完成后整体连接。
smallTail.next = largeDummy.next;
return smallDummy.next;
}
}
func partition(head *ListNode, x int) *ListNode {
smallDummy := &ListNode{}
largeDummy := &ListNode{}
smallTail := smallDummy
largeTail := largeDummy
for head != nil {
next := head.Next
// 已保存原后继,先断开旧连接,让两组始终是独立开链。
head.Next = nil
if head.Val < x {
smallTail.Next = head
smallTail = head
} else {
largeTail.Next = head
largeTail = head
}
head = next
}
// 两组按原顺序收集完成后整体连接。
smallTail.Next = largeDummy.Next
return smallDummy.Next
}
复杂度分析
设链表长度为 $n$。
- 时间复杂度:$O(n)$,每个节点只扫描并追加一次。
- 辅助空间复杂度:$O(1)$,只创建两个哨兵并维护常数个指针,结果复用原链表节点。
关键点总结
[!green]
- 按原顺序扫描并尾插,才能同时保证两组的相对顺序。
- 先保存后继再断开旧连接,使已收集部分与未处理部分各自清楚。
- 两个哨兵统一处理首节点、空链和某一组为空的情况。
易错点总结
[!yellow]
- 分组条件必须为
< x和>= x,不能把等于x的节点放入前组。- 头插会反转每组的相对顺序,不满足稳定分组要求。
- 先断链再保存后继,会失去通往原链剩余节点的入口。
- 复用节点时若不清理原连接,最终拼接可能留下跨组指向甚至形成环。
- 返回时要跳过哨兵,不能把占位节点当成原链中的真实节点。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 328. 奇偶链表 | 中等 | 同样稳定拆成两条链再连接,本题按值与x比较分组,原题按下标奇偶分组。 |
| 21. 合并两个有序链表 | 简单 | 同样使用哑节点和尾指针连接节点,本题维护两组各自原顺序而不是按大小归并。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!