25. K 个一组翻转链表

124 阅读4分钟

【题目】

给你链表的头节点 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) 额外内存空间的算法解决此问题吗?

【题目解析】

解题思路:

解题思路:

本问题要求我们在一定的组大小 k 内翻转链表的节点,而对于不足 k 个的节点组,保持原顺序。为了解决这个问题,我们可以采用以下方法:

  1. 计算链表长度:首先遍历链表以计算出总长度,这有助于我们决定是否需要翻转链表的最后一部分。
  2. 分段处理:按照 k 的大小,将链表分为多个段落,对每个段落单独进行翻转。
  3. 就地翻转:在每个段落内部,采用就地翻转的方式来翻转节点,这样可以保证不使用额外的空间。
  4. 连接段落:翻转完一个段落后,确保翻转后的链表与原链表的未处理部分连接起来。
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode dummy(0);
        dummy.next = head;
        ListNode *prev = &dummy, *curr = head;

        // 计算链表长度
        int len = 0;
        while (curr) {
            len++;
            curr = curr->next;
        }

        // 按 k 个节点一组进行翻转
        while (len >= k) {
            curr = prev->next;
            ListNode* next = curr->next;
            for (int i = 1; i < k; ++i) {
                curr->next = next->next;
                next->next = prev->next;
                prev->next = next;
                next = curr->next;
            }
            prev = curr;
            len -= k;
        }
        return dummy.next;
    }
};

执行:

执行效率.png

【总结】

适用问题类型K 个一组翻转链表问题属于链表操作的高级类别,适合于解决那些需要在链表中进行分段和批量操作的场景。这类问题的特征是有序性和分组性,其中操作不仅限于单个节点,而且还涉及到节点组。类似的问题还包括分段求和、分段排序等,这些问题都要求在链表上执行复杂的、非线性的操作。

使用的算法: 此问题使用了迭代和分治的混合方法来解决,算法的核心在于:

  1. 迭代:迭代方法用于遍历链表,计算长度,并且逐段执行翻转操作。
  2. 分治:分治思想体现在将链表分为多个段,每个段为一组,然后独立地解决每一组内的翻转问题。

算法细节

  • 遍历整个链表以确定长度,以确保是否有足够的节点数进行下一次翻转。
  • 采用分组迭代的方式处理链表,每次处理 k 个节点。
  • 在每组内部,使用指针操作来翻转链表的节点。这涉及到断开和重新连接指针,需要注意的是每次翻转操作后要保持链表的连续性。
  • 对于最后一组节点,如果节点数不足 k 个,则保持原有顺序,不进行翻转。

算法性能

  • 时间复杂度为 O(n),其中 n 是链表的节点总数。尽管我们需要多次遍历链表的部分段落,但每个节点只会被翻转一次。
  • 空间复杂度为 O(1),因为我们没有使用额外的空间来存储节点,而是在原链表上就地进行了翻转。

总结与扩展: 解决这一问题需要对链表有深入的理解,特别是对于节点间指针的操作。通过这个问题,我们不仅学会了链表的分段处理和翻转,还学会了如何在有限的空间内操作数据结构,这是在内存受限的系统编程中非常宝贵的技能。这个问题的解决方案也展示了算法设计中的优化技巧,即如何最小化额外空间的使用,这在处理大数据集或嵌入式系统开发中尤其重要。此外,这类问题的解决方法可以扩展到其他数据结构和更复杂的场景,如多维数组的处理、树的层次翻转等,是提升算法设计能力的重要练习。

题目链接

K 个一组翻转链表