K 个一组翻转链表--分组逆转

0x01.问题

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
输入示例:1->2->3->4->5 k = 3
输出示例:3->2->1->4->5

C++结构体:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 C++函数形式:ListNode* reverseKGroup(ListNode* head, int k)

这个问题实质上是这个问题的升级: 两两交换链表中的节点
建立在这个问题的基础上:反转链表

0x02.简要分析

这又是一个逆转链表的问题,不过它的不同在于是分组逆转,按指定的组来逆转链表。

这其实也并不是一个棘手的问题,因为我们已经有翻转链表的思路,我们只需要把它们分下组就行了。

怎么分组呢?

首先,我们需要确定会造成哪些影响,除了每一个组内部的结构改变了,这个组的前面一个指针的指向其实也发生了改变,而且因为我们使用的是翻转的思路,所以反转后,这个链表的尾部为空,所以我们还需要把它的指向改变。我们还需要一个指针来不断的更新分组的位置。

基于上述思路,我们需要两个指针,一个pre,始终指向当前分组的前一个节点,一个end,控制分组的位置。

我们的具体思路是:

  • end指针每次移动k个位置,确定分组的尾部,如果没有移动k个位置就到末尾了,说明最后那一组不用逆转。
  • 使用一个指针next来保存end的指向。
  • 使用一个指针start来记录每一个组的开头,它应该等于pre->next
  • end指针的指向改为NULL,因为要传进函数去逆转,所以需要截断。
  • pre->next等于逆转后的头指针。
  • start的指向指向next,因为此时start已经是这个分组的尾部了。
  • 更新prestart
  • 跟新endpre
  • 不断迭代,直到end是最后一个元素。

具体逆转思路,请参考 : 反转链表–两种思路

0x03.解决代码–分组逆转

class Solution {
public:
    ListNode*reverse(ListNode*head){
        ListNode*pre=NULL;
        ListNode*curr=head;
        while(curr){
            ListNode*next=curr->next;
            curr->next=pre;
            pre=curr;
            curr=next;
        }
        return pre;
    }
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode*dummy=new ListNode(0);
        dummy->next=head;
        ListNode*pre=dummy;
        ListNode*end=dummy;
        while(end->next){
            for(int i=0;i<k&&end;i++) end=end->next;
            if(!end) break;
            ListNode*next=end->next;
            ListNode*start=pre->next;
            end->next=NULL;
            pre->next=reverse(start);
            start->next=next;
            pre=start;
            end=pre;
        }
        return dummy->next;
    }
};

ATFWUS --Writing By 2020–03–24

你可能感兴趣的:(算法)