跳到正文
第 25 题困难

K 个一组翻转链表

Reverse Nodes in k-Group

每 k 个节点一组翻转链表;最后不足 k 个的节点保持原来的顺序。

在力扣中练习

题目描述

给你链表的头节点 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 个,再在组内反转,最后把三截接回去

这道题可以拆成三个动作:数够一组、组内反转、接回前后两截。

用 groupPrev 指向当前组的前一个节点,从它开始向后数 k 步得到 kth(组尾)。如果数不满,说明剩余不足 k 个,直接结束。组尾后面的 groupNext 必须提前保存,因为反转后组尾会变成新的组头,原来的组头则要指向 groupNext。

反转时把 prev 初始化成 groupNext 而不是 null,这样组内反转完成后,最后一节点自然接回后面的链,不会断。

分步图解

从第 0 个开始数满 3 个:本组是 [2, 7, 4],kth 指向组尾。

groupPrev
#0
当前链表顺序 · 每 k 个一组
2#0
7#1
4#2
9#3
1#4
6#5
3#6
8#7
灰色分组标出已经反转的整组;末尾不足 k 个的节点保持原顺序。
组边界
k=3start=0已反转 0 组
1 / 4
每组的边界由向前数 k 步确定;反转只发生在组内。

反转结束后,groupPrev->next 接到新的组头 kth;然后 groupPrev 移到本组原来的第一个节点,它现在是下一组的前驱。

自拟主例两组各 3 个,最后剩 2 个。第二组反转后是 [6,1,9],不是 [1,9,6];这些节点在原链表里的顺序必须逐一看清。

图解
当前链表顺序 · 每 k 个一组
4第1组
7第1组
2第1组
6第2组
1第2组
9第2组
3#6
8#7
灰色分组标出已经反转的整组;末尾不足 k 个的节点保持原顺序。
组边界
k=3start=6已反转 2 组
普通节点当前操作已确认 / 结果待处理 / 对照
剩下两个节点不足 k 个,不反转,直接保留在链尾。

每组只遍历两次(数长度 + 反转),总时间 O(n),额外空间 O(1)。

时间 O(n)空间 O(1)

易错点

  • prev 初始化为 null:组尾没有接回 groupNext,后面的链全丢。
  • 忘记保存 oldStart:groupPrev 无法移动到下一组的前驱位置。
  • 数不满 k 个仍继续反转:最后不足 k 个的节点会被错误翻转。
  • groupPrev 直接移到 kth:下一轮会跳过或重复处理节点。
对照解法

递归 · 每组反转后接剩余

先确认够 k 个,反转本组,再递归接后面

代码更短,但递归深度为 n/k,最坏 O(n) 调用栈;仅作对照。

递归先向后走 k 步:如果走不满,直接返回原 head,不反转。走满后,node 正好是下一组的起点。

接着反转从 head 开始的 k 个节点,反转后的头是 prev、尾是原来的 head。让 head->next 接上“后面部分递归处理”的结果,返回 prev。

它把“接回下一组”交给递归返回值,省掉了 groupPrev 和 oldStart 的维护,但调用栈随组数增长。

  1. 1向后数 k 个,不足则返回原 head。
  2. 2反转当前 k 个节点。
  3. 3原 head 接到递归结果,返回新组头。
时间 O(n)空间 O(n/k) 调用栈

易错点

  • 数长度时没有保存 groupNext:递归入口会丢。
  • 反转后返回 head 而不是 prev:返回的是组尾。
  • 不足 k 个时仍然反转:尾部顺序被破坏。

代码与演示

主解法配有图解;对照解法用于比较思路、复杂度或实现方式。

演示输入head = [2,7,4,9,1,6,3,8],k = 3

dummy 接到 head,groupPrev 从 dummy 开始;每轮先向前数 k 个节点。

当前链表顺序 · 每 k 个一组
2#0
7#1
4#2
9#3
1#4
6#5
3#6
8#7
灰色分组标出已经反转的整组;末尾不足 k 个的节点保持原顺序。
组边界
k=3start=0已反转 0 组
1 / 5
查看 C++ 代码

延伸阅读

  • 先把“组”看成一个整体,再处理组内反转和组间连接,复杂指针题会清晰很多。
  • 本题是两两交换(24 题)的推广;k=2 时就是两两交换。