一、题目描述
给你链表的头节点 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]
二、思路
相比于简单的反转链表,本题在反转链表的条件上增加了计数条件,这将用到遍历,将反转的链表分成了一些长度相等的小块并连接,反转后,被反转的链表的头节点和尾节点应该怎么样与前后衔接,这些都是我们要解决的问题,我们逐步分析
三、实现步骤
(1)首先封装一个反转链表的函数
ListNode* reversalList(ListNode* head){
ListNode* pre=nullptr;
ListNode* cur=head;
while(cur){
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
(2)因为伴随着反转链表,头节点head会发生变化,所以先创建一个虚拟头节点dummy来固定链表
ListNode* dummy=new ListNode(0);
dummy->next=head;
(3)将链表分成很多长度相等的小块,这里用到了遍历的思想,首先创建两个节点node1 node2指向dummy
ListNode* node1=dummy,*node2=dummy;
while(node1->next){
//将node1指向这个k个规模小块的末尾
for(int i=0;i<k&&node1;i++){
node1=node1->next;
}
}
还有个很重要的条件,因为我们会为node1的下一个节点创建一个指针,所以node1的下一个节点不能为空,否则会报错,这也是我运行中碰到的错误
f(node1==nullptr){
break;
}
(3)第一次找到应该分的小块后,我们就可以进行第一次操作了,给node1的下一个节点定义一个指针node4,以保存该节点,定义一个指针指向该小块的第一个节点,记得断开链表,再将这个小块反转
istNode* node4=node1->next;
ListNode* node3=node2->next;
node1->next=nullptr;
node2->next=reversalList(node3);
(4)反转链表后,下一步进行缝合操作,并移动其它节点准备进行下一次操作
node3->next=node4;
node2=node3;
node1=node3;
(5)直到遍历工作全部完成后,返回最初保存的dummy->next即可
四、具体算法代码实现
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy=new ListNode(0);
dummy->next=head;
ListNode* node1=dummy,*node2=dummy;
while(node1->next){
for(int i=0;i<k&&node1;i++){
node1=node1->next;
}
if(node1==nullptr){
break;
}
ListNode* node4=node1->next;
ListNode* node3=node2->next;
node1->next=nullptr;
node2->next=reversalList(node3);
node3->next=node4;
node2=node3;
node1=node3;
}
return dummy->next;
}
private:
ListNode* reversalList(ListNode* head){
ListNode* pre=nullptr;
ListNode* cur=head;
while(cur){
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
};
五、总结
链表题的解法大体都有相似的地方,先确定要用到些什么步骤和功能,再通过画图模拟过程来加深对过程的理解,再将图里面的东西转换成算法语言即可