C++程序 按块旋转链表

C++程序 按块旋转链表

题目描述

给定一个链表,每k个节点一组进行翻转,返回翻转后的链表。

k是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么将最后剩余的节点保持原样。

例子:

给定这个链表:1->2->3->4->5

当k=2时,应当返回: 2->1->4->3->5

当k=3时,应当返回: 3->2->1->4->5

说明:

你的算法只能使用常数的额外空间。

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

解题思路

首先,我们需要区分出哪些节点需要进行旋转,哪些节点是不需要进行旋转的。以k=3为例,我们可以将链表看做这样的:

1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> …

我们将这些节点按组分配,每组包含k=3个节点,分配之后的结果如下:

[1 -> 2 -> 3] [4 -> 5 -> 6] [7 -> 8 -> 9] …

我们可以看到,每个组的第一个节点就是该组需要进行旋转的节点。

接下来,我们从头到尾遍历每个组的第一个节点,并进行旋转。我们以[1 -> 2 -> 3]组为例,旋转前的链表为:

1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> …

旋转后的链表应为:

3 -> 2 -> 1 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> …

为了完成这个旋转操作,我们需要将每个节点的next指向其前一个节点。

最后,我们将旋转后的每个组连接起来即可得到最终的结果。下面是完整的C++代码:

ListNode* reverseKGroup(ListNode* head, int k) {
    ListNode* new_head = new ListNode(0);  // 创建一个新的头节点,方便链表操作
    new_head->next = head;

    ListNode* pre = new_head;
    ListNode* end = new_head;

    while (end->next != NULL) {
        for (int i = 0; i < k && end != NULL; i++) end = end->next;  // 找到每个组的末尾节点,注意负数节点需要单独处理
        if (end == NULL) break;

        ListNode* start = pre->next;
        ListNode* next = end->next;

        end->next = NULL;  // 断开链表,方便操作

        pre->next = reverseList(start);  // 翻转当前组内的链表

        start->next = next;  // 恢复链表连接

        pre = start;  // 更新pre、end节点
        end = start;
    }

    return new_head->next;
}

ListNode* reverseList(ListNode* head) {  // 翻转链表
    if (head == NULL || head->next == NULL) return head;

    ListNode* new_head = reverseList(head->next);
    head->next->next = head;
    head->next = NULL;

    return new_head;
}

注释中已经解释了每个操作的含义,这里不再重复。

这个算法的时间复杂度为O(n),其中n为链表的长度。空间复杂度为O(1),符合题目要求。

结论

按块旋转链表是一个很常见的链表算法,在很多编程面试中都会出现。掌握这个算法不仅能提升编程能力,也有利于在编程面试中获得更好的成绩。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程

C++ 示例