🌟 题目描述
给你单链表的头节点 head,请你反转链表,并返回反转后的链表。
示例:
输入: 1 → 2 → 3 → 4 → 5 → null
输出: 5 → 4 → 3 → 2 → 1 → null
🔍 为什么用双指针?
反转链表的本质是改变每个节点的 next 指针方向。
如果直接修改指针,很容易“断链”——丢失后续节点。
双指针法通过两个变量(prev 和 curr)协同工作,安全、高效地完成反转,且空间复杂度仅为 O(1) ,是面试官最爱的解法!
💡 双指针解法详解(JavaScript)
✅ 核心思路
-
初始化
prev = null(新链表的尾部),curr = head(当前处理节点)。 -
遍历链表,每一步:
- 先保存
curr.next(防止断链); - 反转指针:
curr.next = prev; - 移动指针:
prev = curr,curr = nextTemp。
- 先保存
-
循环结束后,
prev指向原链表的最后一个节点,即新链表的头节点。
✅ 代码实现
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val === undefined ? 0 : val)
* this.next = (next === undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function(head) {
let prev = null;
let curr = head;
while (curr !== null) {
// 1. 临时保存下一个节点,防止断链
const nextTemp = curr.next;
// 2. 反转当前节点的指针
curr.next = prev;
// 3. 移动双指针
prev = curr;
curr = nextTemp;
}
// prev 即为反转后的新头节点
return prev;
};
✅ 执行过程图解(以 [1→2→3] 为例)
初始: prev = null, curr = 1 → 2 → 3 → null
第1步:
nextTemp = 2
1 → null
prev = 1, curr = 2
第2步:
nextTemp = 3
2 → 1 → null
prev = 2, curr = 3
第3步:
nextTemp = null
3 → 2 → 1 → null
prev = 3, curr = null
结束,返回 prev(即 3)
📊 复杂度分析
| 项目 | 复杂度 |
|---|---|
| 时间复杂度 | O(n) —— 遍历一次链表 |
| 空间复杂度 | O(1) —— 仅用两个指针变量 |
✅ 优势:无递归栈开销,不依赖额外内存,适合长链表和生产环境。
🛠️ 面试小贴士
- 必问问题:“如果链表为空或只有一个节点,代码是否仍正确?”
✅ 答:是的!while循环不会执行,直接返回null或原节点。 - 延伸问题:“如何反转链表的某一段?”
→ 可参考 LeetCode 92(反转链表 II),核心思想类似。
✅ 总结
反转链表是链表操作的基石,而双指针迭代法是最稳健、最高效的解法。
掌握它,不仅能秒杀 LeetCode 206,还能为后续更复杂的链表问题(如回文链表、合并链表等)打下坚实基础。
📌 记住口诀:
先存后指,再移双针;循环结束,prev 即头。