LC206
反转链表:如何不丢掉后半段链表
三指针反转 · 先保存 next 再改 cur.Next
LC206 的核心不是「把箭头反过来」,而是在修改 cur.Next 之前,必须先把原来的后继保存到 next。否则后半段链表会永远失联。
链表 · 三指针先保存 nextO(n) · O(1)
输入
1 2 3 4 5
→
输出
5 4 3 2 1
边界测试 · 切换后整段动画会重算
帧 1/14Scene 1
当前步骤
步骤 1:题目 · 反转 1→2→3→4→5
LC206 的核心不是「把箭头反过来」这么简单。真正要小心的是:在修改 cur.Next 之前,必须先把原来的后继保存到 next 里,否则后半段链表会永远失联。
输入 1→2→3→4→5 · 目标 5→4→3→2→1
三区状态
已反转区(prev 开头)
nil
未处理区(cur 开头)
1→2→3→4→5→nil
临时保护(next)
—
prev 已反转cur 当前next 保护
指针现场
读题:单链表原地反转,O(n) 时间 O(1) 额外空间
代码 · 当前高亮行随帧切换
1func reverseList(head *ListNode) *ListNode {2 var prev *ListNode3 cur := head45 for cur != nil {6 next := cur.Next7 cur.Next = prev8 prev = cur9 cur = next10 }1112 return prev13}
不变量 · 算法为什么对
- · prev 指向已反转好的前缀链表头。
- · cur 指向待反转的第一个节点。
- · next 临时保存 cur 原来的后继,改指针前必须赋值。
- · 每轮顺序:保存 next → 改 cur.Next → prev/cur 右移。
时间线 · 点击跳转
执行轨迹表
点击行跳转| step | prev 链 | cur 链 | next | 当前动作 |
|---|---|---|---|---|
| 1 | nil | 1→2→3→4→5→nil | nil | 读题:单链表原地反转,O(n) 时间 O(1) 额外空间 |
| 2 | nil | 1→nil | nil | 错误:跳过 next := cur.Next,直接改 cur.Next |
| 3 | nil | 1→nil(已断) | nil | 断链:head 只能到 1→nil,2→3→4→5 成孤岛 |
| 4 | nil | 1→2→3→4→5→nil | nil | 策略:next 临时保存 cur 原来的后继 |
| 5 | nil | 1→2→3→4→5→nil | nil | 初始化三指针 |
| 6 | nil | 1→2→3→4→5→nil | 2 | 第一拍:next = cur.Next |
| 7 | nil | 1→nil | 2 | 第二拍:cur.Next = prev |
| 8 | 1→nil | 2→3→4→5→nil | nil | 第三拍:prev=cur; cur=next |
| 10 | 2→1→nil | 3→4→5→nil | 4 | 第 2 轮三拍完成:先保存 next,再改指向,再右移 |
| 11 | 3→2→1→nil | 4→5→nil | 5 | 第 3 轮三拍完成:先保存 next,再改指向,再右移 |
| 12 | 4→3→2→1→nil | 5→nil | nil | 第 4 轮三拍完成:先保存 next,再改指向,再右移 |
| 13 | 5→4→3→2→1→nil | nil | nil | 第 5 轮三拍完成:先保存 next,再改指向,再右移 |
| 13 | 5→4→3→2→1→nil | nil | nil | cur 为空,循环结束 |
| 14 | 5→4→3→2→1→nil | nil | nil | 返回 prev 作为新 head |
面试怎么说
这题用三个指针。prev 表示已经反转好的链表头,cur 表示当前处理节点,next 临时保存 cur.Next,防止修改指针后丢失后半段。每轮先保存 next,再让 cur.Next 指向 prev,然后 prev 和 cur 右移。cur 为空时,prev 就是新头。时间 O(n),空间 O(1)。