25、K个一组反转链表

1、题目描述

给你链表的头节点 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]

提示:

  • 链表中的节点数目为 n
  • 1 <= k <= n <= 5000
  • 0 <= Node.val <= 1000

进阶:你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗?

2、分析

要求:只用O(1)额外内存空间。

还是指针操作。外层只需要借助一个指针记录每批次处理完后cur应该出入的新位置即可。

内层在插入节点的时候也借助个临时指针,这没啥好说的。

 (1)最外层是一个while循环for每批次的处理;
 (2)对于完整的批次进行每批次的处理,处理流程如下:
    1)首先我们要记录下每批次的头结点(被反转后它会作为结果的尾节点),我们需要在一批次结束后用其更新cur指针。
    2)然后就是对批次内的k个元素进行反转,这里的反转其实就是将head指向的每个元素依次作为cur的next插入进去。
    3)期间需要借助一个临时变量,协助完成构建新的连接关系。
 (3)当不足一批次时,退出外层大循环追加到cur指针后面即可。

操作示意图如下。

注:其中phead表示每批次的头节点 batch_head。

3、实现代码

#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <set>
#include <queue>
#include <map>

using namespace std;


struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};
 

/*  1  2  3  4  5
    大致思路: 要用指针存每个group的开头元素。 注: 或者上一个group的最后一个元素也行
    对于完整够数的group逐次反转(由前往后);。
*/

class Solution{
public:
    //判断后续节点是否够完整的一批次(看起来无法统一)
    bool fullBatch(ListNode* head, int k){
        while(head){
            head = head->next;
            k--; //2 1 0
        }
        if (k > 0){
            return false;
        }else{
            return true;
        }
    }

    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode dummy(0, nullptr);
        ListNode* cur = &dummy;
        ListNode* bhead; //记录当前这批的首元素(注:其会作为当前这批处理完后的尾元素,要用它来更新cur指针)
        while(head){
            int batch_size = k;
            bool full = fullBatch(head, k);
            if (!full) break;
            bhead = head;
            while(head!=nullptr && batch_size > 0){
                ListNode* tmp = head;
                head = head->next;
                tmp->next = cur->next;
                cur->next = tmp;
                batch_size--;
            }
            cur = bhead;
        }
        cur->next = head;

        return dummy.next;
    }

    void printList(ListNode* list){
        while(list){
            cout << list->val << ",";
            list = list->next;
        }
        cout << endl;
    }

};



int main()
{
    Solution s1;
    ListNode n15(5);
    ListNode n14(4, &n15);
    ListNode n13(3, &n14);
    ListNode n12(2, &n13);
    ListNode n11(1, &n12);
    s1.printList(&n11);

    int k = 3;
    ListNode* res = s1.reverseKGroup(&n11, k);
    s1.printList(res);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

焱齿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值