K个一组翻转链表 - C++ 含代码
题目(LeetCode 25)
给出一个链表,每 k k k 个节点一组进行翻转,返回翻转后的链表。其中 k k k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k k k 的整数倍,那么最后剩余的节点需保持原有顺序。
说明:1. 算法只能使用常数的额外空间。2. 不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例
对于链表 1 -> 2 -> 3 -> 4 -> 5
当 k = 2 k=2 k=2 时,应当返回 2 -> 1 -> 4 -> 3 -> 5
当 k = 3 k=3 k=3 时,应当返回 3 -> 2 -> 1 -> 4 -> 5
思路
关于这个问题,我们可以使用递归的方法。题目的目标是对链表做K个一组的翻转,直观来看,我们需要把链表从头节点开始,按K个节点一组划分成子链表,再对每个子链表进行单链表翻转,最后把这些子链表连接起来。
使用递归方法时,我们主要关注递归过程的一个单元中进行的操作。
1. 确认递归的回归条件
在本题中,递归的回归条件是当前子链表中的节点不足 k k k 个。当剩余节点不足 k k k 个时,不用进行任何操作,只需要向递归的“上级”返回原指针即可。
ListNode* reverseKGroup(ListNode* head, int k) {
int count = 0;
ListNode* cur = head;
while (count < k && cur) {
count++;
cur = cur->next;
}
if (count < k) return head;
}
2. 翻转当前子链表
经过上一步确认递归的回归条件,我们的代码执行到这里满足以下三点:
(1) 当前子链表节点个数
≥
k
\geq k
≥k;
(2) 待翻转的节点为从head到cur的前一个节点;
(3) cur指针指向下一个待翻转的子链表的第一个节点。
因此,在本次递归中,我们只需要对当前子链表进行翻转,并让翻转后的子链表最后一个节点的next指针指向cur即可。
原地翻转单链表需要三个辅助指针,分别为p指向当前节点、pre指向当前节点的前一个节点以及next指向当前节点的下一个节点。每一步翻转过程中,我们先使用next暂存下一个待翻转的节点,然后将p节点的next指向pre。
ListNode* pre = head;
ListNode* p = head->next;
while (p != cur) {
ListNode* next = p->next;
p->next = pre;
pre = p;
p = next;
}
这一步完成后,当前子链表已经基本完成了内部的翻转,除了最后一个步骤,就是head->next目前没有发生改变。经过翻转后,head已经成为了当前子链表的最后一个节点,根据上面(3),它应该指向下一段链表,也就是cur。但是我们知道从cur开始的新一段子链表也需要做上面的每一步操作,即判断节点是否超过
k
k
k 个,继续翻转。。等等,这不就是递归的递推阶段吗?
3. 递归的递推阶段
因此,我们需要让本次递归的head->next指向下一段子链表翻转后的结果,至于下一次翻转是什么结果,不是本轮递归需要考虑的,我们只要交给它就行了。那么就剩下最后一个问题了,翻转后的子链表,我们需要返回它经过翻转后的新的头节点。我们回头看步骤2中的代码段,循环退出时,p == cur,也就是说,p指向了下一段子链表的开头,那么p的前一个节点pre不就正好是翻转后的新头节点吗(也就是翻转前的尾节点)。所以递归的最后一个环节我们也完成了。
head->next = reverseKGroup(cur, k);
return pre;
递归完整代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
// 递归
// 1. Base case,递归回归条件
int count = 0;
ListNode* cur = head;
while (count < k && cur) {
count++;
cur = cur->next;
}
if (count < k) return head;
// 2. 翻转
ListNode* pre = head;
ListNode* p = head->next;
while (p != cur) {
ListNode* next = p->next;
p->next = pre;
pre = p;
p = next;
}
// 3. 递归递推条件
head->next = reverseKGroup(cur, k);
return pre;
}
};
第一次写博客,难免有不足之处,欢迎大家批评指正,共同交流进步。
578




被折叠的 条评论
为什么被折叠?



