题目描述
给你链表的头节点 head
,每 k
个节点一组进行翻转,请你返回修改后的链表。
k
是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k
的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例
示例 1:
输入:head = [1,2,3,4,5], k = 2 输出:[2,1,4,3,5]
示例 2:
输入:head = [1,2,3,4,5], k = 3 输出:[3,2,1,4,5]
提示:
- 链表中的节点数目为
n
1 <= k <= n <= 5000
0 <= Node.val <= 1000
题解
分析
我们的思路是明确的
- 将链表中的k个节点视为一组数据
- 遍历链表,对划分的每组数据进行链表翻转
- 如果某组数据的节点个数不足k个,则不进行任何操作
问题在于,我们如何定义一组数据,或者说,我们如何定义区间
本题中,我们使用开区间进行定义,如下图所示,假如k=3,则
- 我们要进行链表翻转的区间范围应该是[head,tail]
- left指针指向head的前一个节点,right指向tail的后一个节点,用于每次链表翻转后,重新将翻转后的链表更新链接起来
有关翻转链表的代码细节可以查看
反转链表(图解)_的功能是返回带头结点的单链表l的逆转链表。图解-CSDN博客
在这里我们只给出代码,不做细节说明
std::pair<ListNode*,ListNode*> ListReverse(ListNode*head,ListNode*tail){
ListNode* prev=tail->next;
ListNode* cur=head;
// while(cur!=tail->next){
while(prev!=tail){
ListNode* tmp=cur->next;
cur->next=prev;
prev=cur;
cur=tmp;
}
return {tail,head};
}
需要注意的主要有两点
- 我们将第一个节点的前一个节点视为tail->next,而不再是nullptr
ListNode* prev=tail->next;
- 循环判断的条件应该是prev!=tail,而不能是cur!=tail->next,因为当cur==tail的时候,已经超出了我们要操作的链表范围,不能再继续进行操作
// while(cur!=tail->next){
while(prev!=tail){
然后我们在这组链表翻转结束之后,返回翻转后的头节点和尾节点
return {tail,head};
这样,剩下的操作就是遍历整个链表了,其遍历过程还是比较复杂的,我将整个思路写成了注释
ListNode* reverseKGroup(ListNode* head, int k) {
//创建虚拟头节点
ListNode* dummy=new ListNode();
dummy->next=head;
//创建left指针
ListNode* left=dummy;
while(head){
//创建tail指针,并遍历寻找tail指针的位置
ListNode* tail=left;
for(int i=0;i<k;++i){
tail=tail->next;
//如果在这组的k个数据寻找tail时失败(也就是这组数据不满足k个节点),说明已经处理到最后一组数据了,直接返回即可
if(!tail)
return dummy->next;
}
//right指针记录tail指针的后已经节点位置
ListNode* right=tail->next;
//翻转这组链表
std::pair<ListNode*,ListNode*> res=ListReverse(head,tail);
//更新head指针和tail指针指向新翻转后的链表位置
head=res.first;
tail=res.second;
//重新将翻转后的链表正确链接到原链表中
left->next=head;
tail->next=right;
//更新left指针和head指针为下一组链表相应的位置
left=tail;
head=right;
}
其图解过程如下:
寻找符合条件的k个节点,作为一组数据
链表翻转
更新翻转后的链表的首尾节点位置
重新将翻转后的链表链接到原链表上
处理下一组链表
从处理过程上看,right指针其实可以省略,如下
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy=new ListNode();
dummy->next=head;
ListNode* left=dummy;
while(head){
ListNode* tail=left;
for(int i=0;i<k;++i){
tail=tail->next;
if(!tail)
return dummy->next;
}
// ListNode* right=tail->next;
std::pair<ListNode*,ListNode*> res=ListReverse(head,tail);
head=res.first;
tail=res.second;
left->next=head;
// tail->next=right;
left=tail;
head=tail->next;
}
return dummy->next;
}
整体代码
/**
* 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:
std::pair<ListNode*,ListNode*> ListReverse(ListNode*head,ListNode*tail){
ListNode* prev=tail->next;
ListNode* cur=head;
// while(cur!=tail->next){
while(prev!=tail){
ListNode* tmp=cur->next;
cur->next=prev;
prev=cur;
cur=tmp;
}
return {tail,head};
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy=new ListNode();
dummy->next=head;
ListNode* left=dummy;
while(head){
ListNode* tail=left;
for(int i=0;i<k;++i){
tail=tail->next;
if(!tail)
return dummy->next;
}
// ListNode* right=tail->next;
std::pair<ListNode*,ListNode*> res=ListReverse(head,tail);
head=res.first;
tail=res.second;
left->next=head;
// tail->next=right;
left=tail;
head=tail->next;
}
return dummy->next;
}
};