LeetCode 25:K 个一组翻转链表

LeetCode 25:K 个一组翻转链表

题目思路

这道题要求每 k 个节点翻转一次,如果最后剩余节点不足 k 个,则保持原顺序。

我的第一反应不是直接操作链表指针,而是利用 Deque(双端队列)暂存当前这一组节点。

核心思路:

  1. 先从当前 head 开始,最多取 k 个节点放入 Deque

  2. 如果不足 k 个,说明已经到了最后一组,直接返回原链表。

  3. 如果刚好取到 k 个:

    • 通过 pop() 依次取出节点;
    • 因为前面使用的是 push(),所以取出的顺序正好是原来的逆序;
    • 将这些节点重新连接起来。
  4. 当前这一组处理完之后,对剩余链表 flag 递归执行相同操作。

代码如下:

java 复制代码
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        Deque<ListNode> deque = new ArrayDeque<>();

        ListNode flag = head;
        int num = 0;

        // 先收集 k 个节点
        while (flag != null && num < k) {
            deque.push(flag);
            flag = flag.next;
            num++;
        }

        // 当前节点数量不足 k,保持原顺序
        if (num == k) {
            ListNode newHead = deque.pop();
            head = newHead;

            // 按逆序重新连接
            for (int i = 2; i <= k; i++) {
                newHead.next = deque.pop();
                newHead = newHead.next;
            }

            // 当前组处理完成,递归处理后面的节点
            newHead.next = reverseKGroup(flag, k);

        } else {
            return head;
        }

        return head;
    }
}

最关键的地方:为什么 push() + pop() 就能实现翻转?

假设:

text 复制代码
1 -> 2 -> 3

依次执行:

java 复制代码
deque.push(1);
deque.push(2);
deque.push(3);

队列内部相当于:

text 复制代码
3
2
1

之后依次:

java 复制代码
deque.pop();

得到:

text 复制代码
3 -> 2 -> 1

所以这里实际上是借助 Deque 的**栈特性(后进先出,LIFO)**完成了当前 k 个节点的逆序。

flag 的作用

这里:

java 复制代码
ListNode flag = head;

flag 相当于一个"探路指针"。

收集节点时:

java 复制代码
while(flag != null && num < k){
    deque.push(flag);
    flag = flag.next;
    num++;
}

当循环结束后,如果:

text 复制代码
1 -> 2 -> 3 -> 4 -> 5
        ↑
       flag

假设 k = 3,那么当前组是:

text 复制代码
1 -> 2 -> 3

flag 已经指向:

text 复制代码
4 -> 5

所以当前组翻转完成后:

java 复制代码
newHead.next = reverseKGroup(flag, k);

实际上就是:

text 复制代码
3 -> 2 -> 1 -> 4 -> 5
             ↑
          递归处理

为什么不足 k 个时直接返回?

这是题目的要求:

如果最后剩余的节点不足 k 个,就保持原顺序。

例如:

text 复制代码
1 -> 2 -> 3 -> 4 -> 5
k = 3

第一次处理:

text 复制代码
1 -> 2 -> 3

翻转成:

text 复制代码
3 -> 2 -> 1

剩下:

text 复制代码
4 -> 5

只有 2 个节点,不满足 k = 3,因此:

java 复制代码
if(num == k){
    ...
}else{
    return head;
}

直接返回:

text 复制代码
4 -> 5

最终:

text 复制代码
3 -> 2 -> 1 -> 4 -> 5

这道题的收获

这道题我采用的是:

Deque + 递归

而不是直接进行复杂的链表指针翻转。

这种写法的优点是思路比较直观:先把一组节点"存起来",再按照逆序重新连接。

需要注意的是,这种方法会额外使用 O(k) 的空间。

如果追求这道题的最优空间复杂度,可以进一步学习纯链表指针操作 的写法,把额外空间降低到 O(1)。不过从理解和实现难度来说,目前这个版本已经能够很好地完成题目要求。

时间复杂度为 O(n),每个节点都会被处理一次。

相关推荐
染的人1 小时前
Java 10x15cm面单PDF转换A4格式PDF
java·开发语言·pdf
泡海椒1 小时前
JQuick-java (JQuick-ASM)性能优化原理:字节码生成与缓存机制深度解析
java·缓存·性能优化
Bs_MoneyMagnet1 小时前
基于springboot+vue的家居生活商城平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
微三云 - 廖会灵 (私域系统开发)1 小时前
Spring Boot实战:五级分销定价与自动分佣系统设计与实现
java·spring boot·后端
Json____1 小时前
从零构建在线拍卖系统:Java 全栈开发实践
java·开发语言·管理系统·it学习·wwwoop.com
我命由我123451 小时前
Android Compose 开发,使用 ConstraintLayout,但是引入的是旧的 ConstraintLayout
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
钱栈up2 小时前
mvn compile卡住半小时:定位并修复隐藏的类型不匹配编译错误
java·后端·maven
ysu_03142 小时前
13-图的基础:存储与表示
数据结构·
Zane19942 小时前
Lambda表达式没有类型,为什么还能被当成参数传来传去
java·后端