143. 重排链表(中等)
Blind 75 › 143. 重排链表(中等) (第 4 章)
题目
给定一个单链表的头节点 head,链表原本从左到右依次是 L0 → L1 → … → Ln-1 → Ln。
请把它改成首尾交替的样子:L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …。
注意:必须在原链表上实际交换节点(改 next 指针),不能只是改节点里的 val。
自造示例:[10,20,30,40] → [10,40,20,30];[7,5,9,3,1] → [7,1,5,3,9]。
约束:节点数 1 ~ 5 × 104;节点值 1 ~ 1000;函数应原地重排 head 指向的链表。
思路
一句话:先从中点把链表切成两半,再把后半段反转,最后与前半段交替拼接。
最直白的做法:先遍历一遍把节点存进数组,然后两个指针一个从最左、一个从最右,左右交替取出节点重新接起来。时间 O(n),但额外空间 O(n)——单链表不能下标随机访问,必须先铺一层数组才能“从尾部取数”,不满足原地操作的目标。
关键观察:目标序列其实是两个序列的交错:
- 前半段从头部正向取:
L0, L1, L2, … - 后半段从尾部反向取:
Ln, Ln-1, Ln-2, …
单链表的难点在“从尾部反向取”。但只要把后半段整体反转,反向取就变成了从新头节点正向取;于是左右两个子链都能用各自头节点简单交替拼接。
以 10 → 20 → 30 → 40 → 50 跟踪:
| 步骤 | 链表状态 |
|---|---|
| 原始 | 10 → 20 → 30 → 40 → 50 |
| 快慢指针找中点 | slow 停在 30,second 从 40 开始 |
| 断开 | first = 10 → 20 → 30;second = 40 → 50 |
| 反转后半段 | second = 50 → 40 |
| 交替合并 | 10 → 50 → 20 → 40 → 30 |
因此选定「中点切开 + 反转后半段 + 交替合并」,全程只改指针,空间 O(1)。
解法
三步完成:
- 找中点并断开。 令
fast从head->next出发、slow从head出发;fast一次走两步、slow一次走一步。循环结束后前半段first = head,后半段second = slow->next,再令slow->next为null断开。 - 反转后半段。 用标准三指针
prev / cur / nxt原地反转second。 - 交替合并。 只要
second非空,就保存双方后继,把当前second节点插到当前first节点之后,再双双推进。
下图把上面 3 个步骤串成流程,并逐步演示:


C++
class Solution {
public:
void reorderList(ListNode* head) {
if (!head || !head->next) {
return;
} ListNode* slow = head;
ListNode* fast = head->next;
while (fast && fast->next) {本篇为付费内容
您已阅读试读部分,购买后即可解锁全文。
⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。
还没有评论,来说两句?