碰到仇人,就让他做 K 个一组翻转链表吧

给定链表和正整数 k,从头开始每 k 个节点组成一组:

  • 一组恰好有 k 个节点,就反转这一组;
  • 最后一组不足 k 个,保持原来的顺序;
  • 只能改变节点之间的指针,不能交换节点里的值;
  • 最好原地完成,也就是额外空间为 O(1)。

例如:

输入:1 → 2 → 3 → 4 → 5 → 6 → 7 → 8,k = 3
输出:3 → 2 → 1 → 6 → 5 → 4 → 7 → 8

前两组各有三个节点,所以分别翻转;最后只剩 7 → 8,不够三个,原样留下。

标准解法的四个角色

  1. group_previous:当前分组前面的节点;
  2. kth:当前分组的最后一个节点;
  3. group_next:下一组的第一个节点,也是当前组的边界;
  4. current 和 previous:真正执行局部反转的两根工作指针。

哨兵节点 dummy 的价值,是把“第一组”变成普通组。没有它,第一组前面没有节点,每次接回去都要单独写一套逻辑;有了它,每组都只需要做同一件事:找到 kth、翻转、接回、继续。

完整的 Python 写法如下:

class Solution:
    def reverseKGroup(self, head, k):
        dummy = ListNode(0, head)
        group_previous = dummy

        while True:
            kth = group_previous
            for _ in range(k):
                kth = kth.next
                if kth is None:
                    return dummy.next

            group_next = kth.next

            previous = group_next
            current = group_previous.next
            while current is not group_next:
                next_node = current.next
                current.next = previous
                previous = current
                current = next_node

            old_group_start = group_previous.next
            group_previous.next = kth
            group_previous = old_group_start

这里最值得咂摸的一行是 previous = group_next。普通链表翻转通常从 previous = None 开始,但在这道题里,当前组翻转后的尾节点最终本来就应该指向下一组。因此,我们让 previous 一开始就站在 group_next,组内反转完成时,尾巴也顺手接好了。

input · k = 3

指针翻转现场

步骤 1 / 16

先放一个哨兵节点

dummy 站在链表最前面。它不参与翻转,却让第一组和后续分组使用完全相同的接回逻辑。

主链1 → 2 → 3 → 4 → 5 → 6 → 7 → 8

PythonreverseKGroup
  1. dummy = ListNode(0, head)
  2. group_previous = dummy
  3. while True:
  4. kth = group_previous
  5. for _ in range(k):
  6. kth = kth.next
  7. if kth is None:
  8. return dummy.next
  9. group_next = kth.next
  10. previous = group_next
  11. current = group_previous.next
  12. while current is not group_next:
  13. next_node = current.next
  14. current.next = previous
  15. previous = current
  16. current = next_node
  17. old_group_start = group_previous.next
  18. group_previous.next = kth
  19. group_previous = old_group_start