LeetCode 143中等链表
重排链表 图解题解
一条链表,把头尾交替穿插重排——快慢找中点、反转后半、交替合并,全程不借额外空间。
重排链表分三步:快慢指针找中点(fast 跑两格、slow 跑一格,fast 到头时 slow 停在正中间),从中点把链表劈成两截,把后半段用三个指针 prev/cur/nxt 逐个掉头反转,最后从前半和反转后的后半各取一个节点、交替接在一起——你一个我一个,把 next 指针一根根接好,直到两截都接完。
这道题到底在问什么
把 L0→L1→…→Ln 重排成 L0→Ln→L1→Ln-1…
- 示例
- 1→2→3→4→5 → 1→5→2→4→3
最优解:一步一步想明白
- 3用数组存节点再重连可以做,但链表题重点是原地改指针。
- 4快慢指针找中点,反转后半段,再一前一后交替插入。
- 5slow=3, fast 到尾先用快慢指针找中点:fast 一次两步、slow 一次一步。fast 到尾时,slow 正好停在中间 3。从这里把链表劈成两半。
- 6second: 5 → 4从中点断开:前半 1→2→3、后半 4→5。把后半段三指针反转(prev/cur/nxt 边走边掉头)→ 变成 5→4。
- 7first: 1→2→3 · second: 5→4现在两条链对齐:前半 1→2→3、反转后的后半 5→4。接下来各取一个、交替穿插合并。
- 8first.next=second, 再往后交替接线:1 的 next 接后半的 5,5 的 next 再接前半的 2 —— 1→5→2。每次从两条链各取一个,你一个我一个。
- 9结果: 1→5→2→4→3继续交替到两条链取空:1→5→2→4→3。全程只改指针指向、不新建节点 → 原地完成,O(1) 额外空间。
- 12一句话记住:快慢指针找中点,反转后半段,再一前一后交替插入。
- 15忘断/忘记头 → 丢节点或成环雷区:① 劈两半时 slow.next 要置 null 断开前半尾,否则合并后成环;② 反转后半前先记住它的头。三步(找中点/反转/合并)指针多,顺序错就丢节点。
- 22这题学完不要乱跳,下一步去对应专题 /leetcode-animation/ds?k=linkedlist 连刷同类题;卡住时用 AI 答疑问“我的状态定义哪里不稳”。
⚠️ 容易写错的地方
✗ 错:只照着眼前元素做局部判断
✓ 对:维护动画里的完整状态
本题的答案由状态转移决定,少一个状态就会漏情况。
✗ 错:边界输入不单独跑
✓ 对:先跑空/单元素/重复/极端值
这些输入最容易暴露初始化和越界问题。
完整代码(Python / C++ / Java)
Python
class Solution:
def reorderList(self, head):
if not head or not head.next:
return
slow, fast = head, head.next
while fast and fast.next:
slow = slow.next
fast = fast.next.next
second = slow.next
slow.next = None
prev = None
while second:
nxt = second.next
second.next = prev
prev = second
second = nxt
first, second = head, prev
while second:
n1, n2 = first.next, second.next
first.next = second
second.next = n1
first, second = n1, n2C++
class Solution {
public:
void reorderList(ListNode* head) {
if (!head || !head->next) return;
ListNode *slow = head, *fast = head->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
ListNode* second = slow->next;
slow->next = nullptr;
ListNode* prev = nullptr;
while (second) {
ListNode* nxt = second->next;
second->next = prev;
prev = second;
second = nxt;
}
ListNode *first = head;
second = prev;
while (second) {
ListNode *n1 = first->next, *n2 = second->next;
first->next = second;
second->next = n1;
first = n1;
second = n2;
}
}
};Java
class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null) return;
ListNode slow = head, fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode second = slow.next;
slow.next = null;
ListNode prev = null;
while (second != null) {
ListNode nxt = second.next;
second.next = prev;
prev = second;
second = nxt;
}
ListNode first = head;
second = prev;
while (second != null) {
ListNode n1 = first.next, n2 = second.next;
first.next = second;
second.next = n1;
first = n1;
second = n2;
}
}
}套路模板 · 重排链表迁移骨架
# 1. 定义状态
state = init()
# 2. 按顺序读输入
for x in data:
update(state, x) # 只做本题允许的安全转移
# 3. 从状态里取答案
return answer(state)// 1. init state
for (auto x : data) {
// update state with the same invariant
}
return ans;// 1. init state
for (int x : data) {
// update state with the same invariant
}
return ans;复杂度
时间复杂度
O(n)
每个状态只按核心结构推进有限次
空间复杂度
O(1)
原地改指针:找中点+反转后半+交替合并,只用常数个指针,无栈/堆/表
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 重排链表 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这题的核心状态是什么?+
快慢指针找中点,反转后半段,再一前一后交替插入。
这道题为什么用「链表」,换最直接的暴力解会差在哪?+
链表抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。