P206反转链表
反转思路
将链表反转的过程分为两个区域:
🟦 未反转区(待处理)
原链表中还没有处理(还没有反转指针方向)的部分,从 current
开始一直到链表尾部。
🟩 已反转区(处理完成)
已经反转过来的部分,从 previous
开始,指针方向已经翻转。
我们以一个例子来解释:
假设初始链表是:1 -> 2 -> 3 -> 4 -> 5 -> null
初始状态:
text
🟩 已反转区:null
🟦 未反转区:1 -> 2 -> 3 -> 4 -> 5 -> null
↑
current
第一次循环后:
- 把
current
的next
改指向previous
,也就是让1 -> null
- 然后指针往前推进:
text
🟩 已反转区:1 -> null
🟦 未反转区:2 -> 3 -> 4 -> 5 -> null
↑
current
第二次循环后:
- 把
2 -> 1
- 指针继续前进
text
🟩 已反转区:2 -> 1 -> null
🟦 未反转区:3 -> 4 -> 5 -> null
↑
current
第三次循环后:
text
🟩 已反转区:3 -> 2 -> 1 -> null
🟦 未反转区:4 -> 5 -> null
↑
current
第四次循环后:
text
🟩 已反转区:4 -> 3 -> 2 -> 1 -> null
🟦 未反转区:5 -> null
↑
current
第五次(最后)循环前:
此时 next == null
,current
指向最后一个节点 5。我们还要将 current.next = previous
,也就是 5 -> 4
:
text
🟩 已反转区:5 -> 4 -> 3 -> 2 -> 1 -> null
🟦 未反转区:null
总结逻辑流程:
- 用三个指针遍历链表(
previous
、current
、next
) - 每次循环把
current
指向previous
,并向前推进 - 循环终止时,
current
是原链表的尾部,也就是反转后的头部
java
public ListNode reverseList(ListNode head) {
// 如果链表为空或者链表只有一个节点,直接返回头节点
if (head == null || head.next == null) {
return head;
}
// 初始化三个指针:
// current 指向当前节点
// next 指向下一个节点(即 current 的下一个节点)
// previous 用来记录前一个节点(初始时为空)
ListNode current = head; // 当前节点
ListNode next = current.next; // 下一个节点
ListNode previous = null; // 反转后的部分链表的尾部(初始化为空)
// 遍历链表,直到 next 为 null,即遍历完所有节点
while (next != null) {
// 将 current 的 next 指向 previous,反转当前节点
current.next = previous;
// 移动 previous 和 current,准备反转下一个节点
previous = current; // previous 向前移动,变成当前节点
current = next; // current 向前移动,变成下一个节点
next = next.next; // next 向前移动,变成下一个节点的下一个节点
}
// 最后,current(原始链表的最后一个节点)指向反转后的链表的头部
current.next = previous;
// 返回新的链表头节点
return current;
}
时间复杂度O(N)
空间复杂度O(1)
递归实现
思路:通过递归将链表的尾部逐步返回,等递归到底(也就是 head.next == null)时,从尾节点开始一步步回溯。在回溯过程中,将当前节点的 next.next 指向自身,相当于逐步反转指针方向,同时把自己的 next 指向 null 来断链,最终形成完整的反转链表。
java
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
List next=reverseList(head.next);
head.next.next=head;//反转
head.next=null;
return next;
}
时间复杂度O(N)
空间复杂度ON)