【牛客网题目】链表中的节点每k个一组翻转

目录

描述

题目分析


描述

        将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
        如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
        你不能更改节点中的值,只能更改节点本身。

数据范围: 0≤n≤2000 , 1≤k≤2000 ,链表中每个元素都满足0≤val≤1000;要求空间复杂度 O(1),时间复杂度 O(n)

例如:

        给定的链表是 1→2→3→4→5

        对于k=2 , 你应该返回 2→1→4→3→5

        对于 k=3 , 你应该返回3→2→1→4→5

示例1


输入:{1,2,3,4,5},2

返回值:{2,1,4,3,5}

示例2

输入:{},1

返回值:{}

题目分析

        首先,我们要实现一个reverse函数反转一个区间之内的元素。在此之前我们再简化一下,在给定头节点的情况下对链表进行反转。

// 反转以 a 为头结点的链表
ListNode reverse(ListNode a) {
    ListNode pre, cur, nxt;
    pre = null; cur = a; nxt = a;
    while (cur != null) {
        nxt = cur.next;
        // 逐个结点反转
        cur.next = pre;
        // 更新指针位置
        pre = cur;
        cur = nxt;
    }
    // 返回反转后的头结点
    return pre;
}

        反转以a为头结点的链表其实就是反转a到null之间的结点,那么反转a到b之间的结点就只需要吧null改为b是不是就可以实现了?下面给出反转a到b之间节点的代码:

/** 反转区间 [a, b) 的元素,注意是左闭右开 */
ListNode reverse(ListNode a, ListNode b) {
    ListNode pre, cur, nxt;
    pre = null; cur = a; nxt = a;
    // while 终止的条件改一下就行了
    while (cur != b) {
        nxt = cur.next;
        cur.next = pre;
        pre = cur;
        cur = nxt;
    }
    // 返回反转后的头结点
    return pre;
}

        现在我们迭代实现了反转部分链表的功能,那么只需要遍历种反转链表不就是可以了么,下面是完整代码:

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        auto node=head;
        for (int i=0;inext;
        }
        auto res = reverse(head, node); // 翻转长度是k的链表
        head->next = reverseKGroup(node, k); // 递归处理下一个长度是k的链表
        return res; //返回头指针
    }
private:
    //reverse函数实现反转a到b之间的结点
    ListNode* reverse(ListNode* left, ListNode* right) {
        auto pre=right;
        while (left!=right) {
            auto node=left->next;
            left->next=pre;
            pre = left;
            left = node;
        }
        return pre;
    }
};

时间复杂度:O(n)
空间复杂度:O(1) 没有使用额外空间
优缺点:时间复杂度低,但是思考过程难 不容易向到

你可能感兴趣的:(牛客网题解分析,链表,算法,数据结构)