解题思路

本题目的核心显然是解决对每一组k个节点的翻转,以及每组之间的连接,试想:
对每一组k个节点写一个翻转函数,以这一组的之前一个节点 prev 以及 k 作为参数,最终返回翻转后这一组的尾节点,此尾节点将作为下一组的prev节点,当某一组不足k个节点时,不翻转,输出链表
解题步骤

我们的解题步骤如下:

初始化一个prev节点位于整个链表之前
设置哨兵节点ans等于prev,便于最后输出链表
判断以prev->next为起点是否存在k个节点,若存在,调用翻转函数进行翻转
更新prev为第一组节点翻转后的尾节点
重复3、4步
输出链表

翻转函数的写法(递归)

解题思路说完了,再讲讲这个翻转函数的写法:
每一组k个节点的翻转,显然可以等价于先对前k-1个节点进行翻转,再将第k个节点放到这k-1个节点的前面,故翻转函数的过程可以表示如下:

  1. 判断k是否大于等于2
  2. 若k不大于2,也就是k=1,一个节点显然是不用翻转的,这也是递归的出口,此节点也就是翻转后的尾节点,直接返回该节点
  3. 若k>=2,调用参数为k-1的翻转函数将前k-1个节点翻转
  4. 将前k-1个节点翻转后的结果再和第k个节点交换
  5. 直到递归的出口,也就是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;
        }
    }