解题思路
本题目的核心显然是解决对每一组k个节点的翻转,以及每组之间的连接,试想:
对每一组k个节点写一个翻转函数,以这一组的之前一个节点 prev 以及 k 作为参数,最终返回翻转后这一组的尾节点,此尾节点将作为下一组的prev节点,当某一组不足k个节点时,不翻转,输出链表
解题步骤
我们的解题步骤如下:
初始化一个prev节点位于整个链表之前 设置哨兵节点ans等于prev,便于最后输出链表 判断以prev->next为起点是否存在k个节点,若存在,调用翻转函数进行翻转 更新prev为第一组节点翻转后的尾节点 重复3、4步 输出链表
翻转函数的写法(递归)
解题思路说完了,再讲讲这个翻转函数的写法:
每一组k个节点的翻转,显然可以等价于先对前k-1个节点进行翻转,再将第k个节点放到这k-1个节点的前面,故翻转函数的过程可以表示如下:
- 判断k是否大于等于2
- 若k不大于2,也就是k=1,一个节点显然是不用翻转的,这也是递归的出口,此节点也就是翻转后的尾节点,直接返回该节点
- 若k>=2,调用参数为k-1的翻转函数将前k-1个节点翻转
- 将前k-1个节点翻转后的结果再和第k个节点交换
- 直到递归的出口,也就是k=1
ListNode* reverseKGroup(ListNode* head, int k) { ListNode* prev=new ListNode(0); prev->next=head; //设置哨兵节点 ans ListNode* ans=prev; //当剩下的节点数不足 k 时,退出循环 while(swapK(prev,k)!=nullptr){ swapK(prev,k); //将前节点 prevv 更新为前一组 k 个节点交换后的尾节点 prev=swapK(prev,k); } return ans->next; } //交换 k 个节点的函数,以每一组k个节点的前一个节点,记为前节点 prev,和 k 为参数 ListNode* swapK(ListNode* prev,int k){ //将每一个 k 个节点划分成 前 k-1 个节点和尾节点 //这里的 tail 是每一组 k 个节点的尾节点 ListNode* tail; //这里的 head 是 前 k-1 个节点 经过翻转后的尾节点,因他在 k 个节点的尾节点之前,命名head ListNode* head; if(k>=2){ tail=prev; //此循环使 tail 指向本组尾节点 for(int i=0;i<k;i++){ tail=tail->next; //判断本组节点够不够 k 个 if(!tail) return nullptr; } //递归的思想,每一组 k 个节点的翻转共两步:1)对前 k-1 个节点进行翻转,2)再把尾节点放到这 k-1 个节点的前面 //这是 1)步 head=swapK(prev,k-1); //这是 2)步 head->next=tail->next; tail->next=prev->next; prev->next=tail; //返回尾节点,用作下一组的 prev 节点 return head; } else{ //递归的出口 return prev->next; } }