(LeetCodeHot100)206. 反转链表——reverse-linked-list
(LeetCodeHot100)206. 反转链表——reverse-linked-list
zhangzhang206. 反转链表——reverse-linked-list
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
1 | 输入:head = [1,2,3,4,5] |
示例 2:
1 | 输入:head = [1,2] |
示例 3:
1 | 输入:head = [] |
提示:
- 链表中节点的数目范围是
[0, 5000] -5000 <= Node.val <= 5000
我的答案
- 不到一分钟就写出来了,说明之前写数据结构C++的PTA作业还是有用的
1 | class Solution { |
官方解答
方法一:迭代
假设链表为 1→2→3→∅,我们想要把它改成 ∅←1←2←3。
在遍历链表时,将当前节点的 next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。
1 | class Solution { |
复杂度分析
- 时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
- 空间复杂度:O(1)。
方法二:递归
递归版本稍微复杂一些,其关键在于反向工作。假设链表的其余部分已经被反转,现在应该如何反转它前面的部分?
假设链表为:
1 | n1→…→nk−1→nk→nk+1→…→nm→∅ |
若从节点 nk+1 到 nm 已经被反转,而我们正处于 nk。
1 | n1→…→nk−1→nk→nk+1←…←nm |
我们希望 nk+1 的下一个节点指向 nk。
所以,nk.next*.next=*nk。
需要注意的是 n1 的下一个节点必须指向 ∅。如果忽略了这一点,链表中可能会产生环。
1 | class Solution { |
复杂度分析
- 时间复杂度:O(n),其中 n 是链表的长度。需要对链表的每个节点进行反转操作。
- 空间复杂度:O(n),其中 n 是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n 层。
用具体例子拆解每一步
假设链表是 1 → 2 → 3 → 4 → null,我们跟踪 reverseList(head=1) 的执行过程:
1. 第一步:递归 “递到底”(找最后一个节点)
递归函数会不断调用 reverseList(head.next),直到触发终止条件(head.next == null):
reverseList(1)→ 调用reverseList(2)reverseList(2)→ 调用reverseList(3)reverseList(3)→ 调用reverseList(4)reverseList(4):此时head=4,head.next=null(终止条件),返回4(这是反转后的新头节点newHead)。
此时递归开始 “往回走”(回溯),每一步都处理当前节点和反转后子链表的连接。
2. 第二步:回溯处理 reverseList(3)
此时 head=3,子问题 reverseList(4) 返回 newHead=4(反转后的子链表是 4 → null):
- 现在要把3接到子链表上:
- 原关系:
3 → 4(head=3,head.next=4) - 反转需求:让
4 → 3,即head.next.next = head(4的下一个指向3) - 避免环:
3的下一个必须置空(head.next = null),否则3 → 4 → 3成环
- 原关系:
- 处理后子链表变为
4 → 3 → null,返回newHead=4(始终返回最末尾的节点作为新头)。
3. 第三步:回溯处理 reverseList(2)
head=2,子问题返回 newHead=4(子链表 4 → 3 → null):
head.next=3,执行3.next=2(head.next.next=head)2.next=null(避免环)- 处理后子链表
4 → 3 → 2 → null,返回newHead=4。
4. 第四步:回溯处理 reverseList(1)(最初的调用)
head=1,子问题返回 newHead=4(子链表 4 → 3 → 2 → null):
head.next=2,执行2.next=1(head.next.next=head)1.next=null(避免环)- 最终链表
4 → 3 → 2 → 1 → null,返回newHead=4。




