给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

https://leetcode.cn/problems/reverse-linked-list/description/

迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public ListNode reverseList(ListNode head) {
ListNode curr = head;
ListNode pre = null;


while (curr != null) {
// 1. 暂存下一个节点,并声明类型
ListNode next = curr.next;

// 2. 反转:当前节点的 next 指向前一个节点
curr.next = pre;

// 3. 指针整体向后移动一步(注意顺序:先挪 pre,再挪 curr)
pre = curr; // pre 来到刚才反转好的节点位置
curr = next; // curr 走向下一个待处理的节点
}

// 4. 返回新链表的头节点
return pre;
}

}


递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public ListNode reverseList(ListNode head) {
// 1. 终止条件:如果链表为空,或者只有一个节点,直接返回
if (head == null || head.next == null) {
return head;
}

// 2. 递归调用:反转以 head.next 为头节点的后续链表
// 记住:这里的 newHead 永远是原链表的最后一个节点,它会一路被向上返回
ListNode newHead = reverseList(head.next);

// 3. 核心反转逻辑(发生在“归来”阶段):
// 此时 head.next 代表下一个节点。把下一个节点的 next 指向当前 head,实现局部反转
head.next.next = head;

// 4. 断开当前节点原来的向后指针,防止产生环
head.next = null;

// 5. 返回新链表的头节点
return newHead;
}

}


K 个一组翻转链表

https://leetcode.cn/problems/reverse-nodes-in-k-group/description/

流程:

  1. 分组:从头数 k 个为一组,不足 k 直接停
  2. 段内反转:每一组内部反转
  3. 接链:把反转后的段头接到前驱、段尾接下一组头

使用虚拟头节点 dummy确保头节点没变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
while (true) {
ListNode tail = pre;
for (int i = 0; i < k; i++) {
tail = tail.next;
if (tail == null) return dummy.next;
}
ListNode nextGroup = tail.next;
ListNode newHead = reverseK(pre.next, nextGroup, k); // 调用递归版
ListNode newTail = pre.next;
pre.next = newHead;
pre = newTail;
}
}

// 递归
private ListNode reverseK(ListNode start, ListNode after, int k) {
if (k == 1) {
start.next = after;
return start;
}
ListNode newHead = reverseK(start.next, after, k - 1);
start.next.next = start;
start.next = after;
return newHead;
}
}

反转链表 II

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

示例 1:

img

1
2
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

区间反转 = 把区间起点挪到链头 + 反转前 N 个节点,递归负责 “挪”,reverse 负责 “反转”。

① reverse(head, n):反转前 n 个节点,返回新头

  • 递归到底(n==1)时,head 是区间最后一个节点,记下它右边那个节点 s(successor);
  • 回溯时 head.next.next = head 让后继指回自己,head.next = s 把原头(变尾巴)接回右半段。

② reverseBetween(head, left, right):把区间往前挪

  • left == 1:区间起点就是链头 → 交给 reverse(head, right),必须 return;
  • left > 1:跳过 head,递归处理 head.next,区间整体 left-1, right-1,再把返回的新头接到 head.next。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

class Solution {
// successor:记录反转区间右侧第一个节点(用于反转后接回右半段)
ListNode s;

// 反转以 head 为头的前 n 个节点,返回新头
public ListNode reverse(ListNode head, int n) {
// 递归到底:head 正好是区间最后一个节点
if (n == 1) {
s = head.next; // 记下第 n+1 个节点(右半段的头)
return head; // 区间最后一个节点成为新头
}

// 先递归反转后面 n-1 个
ListNode newHead = reverse(head.next, n - 1);

head.next.next = head;
head.next = s;

return newHead;
}

// 反转链表从位置 left 到 right 的区间
public ListNode reverseBetween(ListNode head, int left, int right) {
// 区间起点就是链头 → 直接反转前 right 个节点
if (left == 1) {
return reverse(head, right);
}

// 跳过当前 head,区间整体前移一格,反转完接到 head 后面
head.next = reverseBetween(head.next, left - 1, right - 1);
return head;
}
}