25.k个一组翻转链表

🍍 25.k个一组翻转链表

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

img

注意,不足k个的链表不能翻转,也就是上面的[4,5]不能翻转

思路

基本思想

为了将链表中的节点k个一组进行翻转,同时不足k个的链表不能翻转,需要将链表中的节点进行分组,为了统一,先将不足k个的节点也翻转,之后如果判断出当前链表不足k个,那么就再翻转回来即可,翻转两次还是回到原来的形状

每形成一个翻转小链表,就将头结点保存到一个容器中,所有的节点翻转结束之后,将这些小链表合并成一个大链表

为了分组,需要记录当前遍历到了哪个节点上,一旦当前遍历到了第k个节点,说明形成了一个完整的翻转小链表,此时将这个小链表保存到容器中,同时重新开始翻转,翻转时使用了一个虚拟头结点,可以很好的记录当前翻转小链表的头结点

之后单独处理最后一个小链表,如果最后一个小链表的节点个数不足k个,那么就不能翻转,此时需要将其翻转回来

处理完所有的小链表之后,将其拼接在一起即可

执行流程

  1. 使用头插法进行链表翻转,虚拟头结点做辅助
  2. 当形成k个节点的翻转小链表之后,将其保存到容器中,之后清空虚拟头结点,重新开始翻转
  3. 所有的节点翻转完毕之后,需要单独处理最后一个小链表
  4. 如果最后一个小链表不足k个,就不能翻转,需要还原(再翻转一次)
  5. 如果最后一个小链表刚好k个,那么就可以翻转
  6. 之后将一个个的游离的小链表合并起来,返回最终的答案

代码

根据以上分析,得出以下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Solution {
public:
    //每次取k个进行翻转,之后将翻转之后的小链表进行合并
    //长度不足k的链表不进行翻转
    ListNode* reverseKGroup(ListNode* head, int k) {
        //只有一个节点
        if(head->next==nullptr)
            return head;
        //到这里至少两个节点,每k次一存,之后重新开始翻转
        vector<ListNode*> res;
        ListNode* dummyHead=new ListNode(0);
        dummyHead->next=nullptr;
        ListNode* node=head;
        ListNode* temp;
        int index=0;
        while(node!=nullptr){
            if(index!=0&&index%k==0){
                //保存每一个小翻转链表的头节点
                res.push_back(dummyHead->next);
                dummyHead->next=nullptr;
            }
            //反转
            temp=node->next;
            node->next=dummyHead->next;
            dummyHead->next=node;

            node=temp;
            index++;
        }
        //处理最后一个小链表
        if(index%k==0)
            res.push_back(dummyHead->next);
        //说明不足k个,不能反转,所以需要翻转回来,相当于还原
        else{
            node=dummyHead->next;
            dummyHead->next=nullptr;
            while(node!=nullptr){
                temp=node->next;
                
                node->next=dummyHead->next;
                dummyHead->next=node;
                node=temp;
            }
            res.push_back(dummyHead->next);
        }
        dummyHead->next=nullptr;
        //小链表合并
        for(int i=0;i<res.size();++i){
            //刚开始使用dummyhead连接
            if(i==0)
                dummyHead->next=res[i];
            //之后使用node连接
            else{
                node->next=res[i];
            }
            while(res[i]->next!=nullptr){
                res[i]=res[i]->next;
            }
            //记住当前小链表的最后一个节点,与下一个小链表的头结点连接起来
            node=res[i];
        }
        return dummyHead->next;
    }
    
};

总结

将问题分割成一个一个的小问题,之后再合并,主要是最后一个小链表需要单独处理,之后全是代码模拟,每k个一翻转,之后将所有的小链表合并