8.3链表专题:LeetCode 143. 重排链表
链表重排的三大核心操作|快慢指针+逆序+合并详解LeetCode143
1. 题目链接
LeetCode 143. 重排链表
2. 题目描述
给定一个单链表,要求按照「首→尾→次首→次尾」的顺序重新排列节点。要求必须原地修改链表,且不能修改节点值。
示例说明
输入:1 → 2 → 3 → 4
输出:1 → 4 → 2 → 3
输入:1 → 2 → 3 → 4 → 5
输出:1 → 5 → 2 → 4 → 3
3. 示例分析
示例1:偶数长度链表
原始链表:
1 → 2 → 3 → 4
处理过程:
- 拆分为前段
1→2
和后段3→4
- 后段逆序为
4→3
- 交替合并为
1→4→2→3
示例2:奇数长度链表
原始链表:
1 → 2 → 3 → 4 → 5
处理过程:
- 拆分为前段
1→2→3
和后段4→5
- 后段逆序为
5→4
- 交替合并为
1→5→2→4→3
4. 算法思路
三阶段处理框架
-
快慢指针切分链表
- 慢指针初始指向头节点,快指针初始指向第二个节点(关键设计)
- 慢指针每次走1步,快指针每次走2步
- 最终慢指针指向中间节点的前驱节点
-
头插法逆序后半段
原链表:3 → 4 → 5 逆序后:5 → 4 → 3
-
双指针交替合并
前段指针:1 → 2 → 3 后段指针:5 → 4 合并结果:1→5→2→4→3
5. 边界条件与注意事项
关键边界处理
- 短链表特判:长度≤2时直接返回
- 奇数长度处理:中间节点归前段
- 指针安全防护:
slow->next = nullptr; // 切断前后段联系
易错点警示
- 快慢指针初始化:快指针初始化为
head->next
确保中点正确分割 - 内存泄漏风险:创建的辅助头节点必须显式释放
- 合并顺序错误:必须交替插入前后段节点
6. 代码实现
class Solution {
public:
void reorderList(ListNode* head) {
if (!head || !head->next || !head->next->next) return;
/* 阶段一:快慢指针找中点 */
ListNode *slow = head, *fast = head->next; // 关键初始化
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
/* 阶段二:逆序后半段链表 */
ListNode* head2 = new ListNode(0); // 辅助头节点
ListNode* cur = slow->next;
slow->next = nullptr; // 切断前后段
while (cur) {
ListNode* next = cur->next;
cur->next = head2->next;
head2->next = cur;
cur = next;
}
/* 阶段三:双指针交替合并 */
ListNode* ret = new ListNode(0); // 虚拟头节点
ListNode* prev = ret;
ListNode *cur1 = head, *cur2 = head2->next;
while (cur1) {
prev->next = cur1; // 插入前段节点
cur1 = cur1->next;
prev = prev->next;
if (cur2) { // 插入后段节点
prev->next = cur2;
cur2 = cur2->next;
prev = prev->next;
}
}
// 内存释放
delete head2;
delete ret;
}
};
关键代码解析
-
快慢指针切分
- 快指针初始指向
head->next
,确保链表长度为偶数时,慢指针停留在前半段末尾 slow->next = nullptr
彻底断开前后段联系
- 快指针初始指向
-
头插法逆序
- 创建辅助头节点
head2
简化逆序操作 - 每次将当前节点插入头节点后,实现逆序
- 创建辅助头节点
-
安全合并
- 虚拟头节点
ret
统一处理合并逻辑 - 交替插入前后段节点,优先处理前段链表
- 虚拟头节点
复杂度分析与优化
- 时间复杂度:O(n)
三阶段均只需单次遍历链表 - 空间复杂度:O(1)
仅使用固定数量的指针变量
优化点:合并阶段可直接复用原链表节点,无需创建新链表,但需注意指针操作顺序。
总结
本解法通过「快慢指针定位→头插法逆序→双指针合并」的三段式处理,以O(n)时间复杂度实现链表重排。
核心技巧:
- 快慢指针初始值的特殊设置,确保中点分割准确性
- 头插法逆序操作的高效实现
- 虚拟头节点简化边界条件处理
该解法体现了链表操作中指针控制的精髓,掌握后能应对K个一组翻转等进阶题型。