【翻转链表】LeetCode 25. K 个一组翻转链表
题目
https://leetcode.cn/problems/reverse-nodes-in-k-group/description/
题解
首先分析特殊情况,当链表长度 \(n\) 与 \(k\) 相等的情况。以测试用例 \(head = [0,1,2,3], k = 4\) 进行分析:

使用指针 \(first\) 指向头结点,指针 \(last\) 指向尾结点:

容易看出,将指针 \(first\) 依次后移到指针 \(last\) 所指向的节点的前一个节点为止,并使用头插法逐个插入到指针 \(last\) 所指向的节点之后,即可实现 \(n == k\) 的情况下的链表翻转:
- 首先使用指针 \(node\) 指向 \(first -> next\),以保证可以遍历链表(这个较为简单就不画出了)。
- 将指针 \(last -> next\) 赋予指针 \(first -> next\)
![]()
- 将指针 \(first\) 赋予指针 \(last -> next\)
![]()
- 随后,将指针 \(node\) 赋予 \(first\)
![]()
- 重复上述步骤1~4,直到指针 \(first\) 与指针 \(last\) 指向的节点是相同的节点就立刻停止,最后得到以下链表:
![]()
现在拥有了翻转整个链表的思路,进一步思考如何只翻转链表中的 \(k(k < n)\) 个节点?
以测试用例 \(head = [0,1,2,3], k = 2\) 进行分析:
- 首先让指针 \(first\) 指向第 \(1\) 个节点,指针 \(last\) 指向第 \(k = 2\) 个节点:
![]()
- 按照之前分析的思路,经过翻转,可以得到:
![]()
- 此时无法简单重复之前的步骤,而是需要让指针 \(first\) 指向第 \(k + 1 = 3\) 个节点,让指针 \(last\) 指向第 \(k + k = 4\) 个节点:
![]()
- 此时,尝试使用 \(n == k\) 时的翻转链表的思路进行翻转,得到的结果如下:
![]()
容易发现,使用 \(n == k\) 时的翻转链表的思路,对 \(k < n\) 的情况并不适用。进一步思考问题出在哪里?
答:问题出在第 \(k + 1 = 3\) 个节点之前的节点的指针 \(next\) 未指向第 \(k + k = 4\) 个节点。 - 因此,需要额外维护指针 \(first\) 指向的节点之前的第一个节点 \(pre\),并在每次执行翻转操作后,就将最新的指针 \(first\) 赋予指针 \(pre -> next\)。为了统一操作,使整个链表的最前面 \(k\) 个节点也能用节点 \(pre\) 维护,可以额外引入一个节点作为 \(pre\) 节点,将 \(pre -> next\) 初始化为 \(head\)。
![]()
- 最后,可以使用一个 int 型的整数去维护节点个数,当该整数为 \(k\) 的整数倍时,就将这连续的 \(k\) 个节点进行翻转,这样就可以实现 \(k\) 个一组的翻转链表操作了。
参考代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (k == 1) return head;
ListNode* f = new ListNode(), * l, * right;
f -> next = head;
right = head;
for (int i = 1; ; ++ i) {
if (right -> next == nullptr && i % k) break;
if (i % k == 0) {
l = f -> next;
while (f -> next != right) {
ListNode* node = f -> next -> next;
f -> next -> next = right -> next;
right -> next = f -> next;
f -> next = node;
}
if (i == k) {
head = f -> next;
}
f = l;
right = f -> next;
if (right == nullptr) break;
} else {
right = right -> next;
}
}
return head;
}
};
若是最后剩余的节点不足 \(k\) 个,也需要进行翻转的,则使用如下代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (k == 1) return head;
ListNode* f = new ListNode(), * l, * right;
f -> next = head;
right = head;
bool flag = true;
for (int i = 1; ; ++ i) {
if (i % k == 0 || right -> next == nullptr) {
l = f -> next;
while (f -> next != right) {
ListNode* node = f -> next -> next;
f -> next -> next = right -> next;
right -> next = f -> next;
f -> next = node;
}
if (flag) {
flag = false;
head = f -> next;
}
if (right -> next == nullptr) break;
f = l;
right = f -> next;
if (right == nullptr) break;
} else {
right = right -> next;
}
}
return head;
}
};









浙公网安备 33010602011771号