Java版LeetCode热题100之「K 个一组翻转链表」详解

Java版LeetCode热题100之「K 个一组翻转链表」详解

本文约9200字,全面深入剖析 LeetCode 第25题《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个的尾部保持原序。

核心挑战:

  1. 分组判断:如何高效判断当前组是否满足k个节点?
  2. 局部反转:如何只反转指定区间的子链表?
  3. 连接上下文:反转后,如何将子链表重新接入原链表?
  4. 头节点变更:第一组反转后,原head不再是头节点,如何正确返回?
  5. 边界处理:空链表、k=1k=n等特殊情况。

关键观察:

  • 每次操作涉及四个关键节点
    • pre:当前组的前驱(用于连接新头)
    • head:当前组的头
    • tail:当前组的尾
    • nextGroup:下一组的头(即tail.next
  • 反转后,原head变成尾,原tail变成头;
  • 必须在反转前保存nextGroup,否则链表断裂;
  • 使用虚拟头节点(hair)可统一处理头节点变更问题。

三、答案构思

总体策略:模拟 + 分段反转

  1. 创建虚拟头节点hairhair.next = head
  2. 初始化pre = hairhead = original head
  3. 循环处理每一组:
    • pre出发,走k步找到tail
    • 若中途tail == null,说明不足k个,直接返回;
    • 保存nextGroup = tail.next
    • 反转[head, tail]区间;
    • 将反转后的子链表接回:pre.next = newHeadnewTail.next = nextGroup
    • 更新pre = newTailhead = nextGroup
  4. 返回hair.next

子问题:如何反转指定区间的链表?

参考「206. 反转链表」,但需注意:

  • 反转终止条件不是null,而是tail
  • 初始prev应设为tail.next(即nextGroup),确保反转后尾部正确连接。

本题是“链表操作综合题”:融合了哑节点、指针移动、区间反转、连接修复等技巧。


四、完整答案(Java 实现)

/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */classSolution{publicListNodereverseKGroup(ListNodehead,intk){// 创建虚拟头节点("hair"),简化头节点处理ListNodehair=newListNode(0);hair.next=head;// pre 始终指向当前组的前驱节点ListNodepre=hair;// 循环处理每一组while(head!=null){// 1. 找到当前组的尾节点 tailListNodetail=pre;for(inti=0;i<k;i++){tail=tail.next;if(tail==null){// 不足 k 个,直接返回returnhair.next;}}// 2. 保存下一组的头节点ListNodenextGroup=tail.next;// 3. 反转 [head, tail] 区间// myReverse 返回 {newHead, newTail}ListNode[]reversed=myReverse(head,tail);ListNodenewHead=reversed[0];ListNodenewTail=reversed[1];// 4. 将反转后的子链表接回原链表pre.next=newHead;// 前驱连接新头newTail.next=nextGroup;// 新尾连接下一组// 5. 更新指针,准备处理下一组pre=newTail;head=nextGroup;}returnhair.next;}/** * 反转从 head 到 tail 的子链表(闭区间) * @return {newHead, newTail} 即 {tail, head} */privateListNode[]myReverse(ListNodehead,ListNodetail){// 关键:初始 prev 设为 tail.next,确保反转后尾部指向正确位置ListNodeprev=tail.next;ListNodecurrent=head;// 当 prev == tail 时,说明 head 到 tail 已全部反转while(prev!=tail){ListNodenextTemp=current.next;current.next=prev;prev=current;current=nextTemp;}// 返回 {新头, 新尾} = {原 tail, 原 head}returnnewListNode[]{tail,head};}}

该解法满足进阶要求:O(1) 额外空间!


五、代码分析

1. 虚拟头节点(hair)的作用

  • 问题:第一组反转后,原head不再是头节点,如何返回正确结果?
  • 解决方案:创建hair节点,hair.next = head
  • 效果
    • 无论是否反转,最终头节点始终是hair.next
    • pre初始为hair,天然成为第一组的“前驱”。

2. 分组与长度检查

ListNodetail=pre;for(inti=0;i<k;i++){tail=tail.next;if(tail==null)returnhair.next;}
  • pre(前驱)出发,走k步到达tail
  • 若中途tail == null,说明剩余节点不足k个,直接返回。

3. 子链表反转逻辑(myReverse)

[1,2,3]为例(k=3):

  • 初始:head=1,tail=3,prev = tail.next = 4
  • 反转过程:
    • 1 → 4(断开原连接,指向下一组)
    • 2 → 1
    • 3 → 2
  • 最终:3 → 2 → 1 → 4,返回{3, 1}

⚠️关键点prev初始值必须是tail.next,否则反转后尾部会指向null,导致链表断裂!

4. 连接修复

pre.next=newHead;// 前一组的尾 → 新头newTail.next=nextGroup;// 新尾 → 下一组的头
  • 完美衔接三部分:前缀 + 反转组 + 后缀

六、时间复杂度和空间复杂度分析

项目复杂度说明
时间复杂度O(n)每个节点被访问常数次(找 tail + 反转)
空间复杂度O(1)仅使用常数个额外指针

其中n为链表长度。

  • 时间详解
    • 外层循环执行⌊n/k⌋次;
    • 每次循环:找tail耗时 O(k),反转耗时 O(k);
    • 总时间 =⌊n/k⌋ × 2k ≈ 2n → O(n)
  • 空间:无递归、无栈,纯迭代,满足进阶要求。

七、常见问题解答(FAQ)

Q1:为什么 myReverse 的终止条件是prev != tail


我们希望反转headtail的所有节点。
初始prev = tail.next,每次循环prev前移一个节点。
prev == tail时,说明tail也已完成反转(其next已指向原前驱),此时停止。
例如[1,2,3]

  • 初始:prev=4
  • 第1轮:prev=1
  • 第2轮:prev=2
  • 第3轮:prev=3(== tail),停止

Q2:能否先遍历一次获取总长度,再分组?

:可以,但不推荐。

  • 优点:提前知道哪些组需要反转;
  • 缺点:需要两次遍历,且代码更复杂;
    本题解法只需一次遍历,更优雅。

Q3:如果 k=1,会发生什么?

:每个节点自成一组,反转后顺序不变。
代码仍正确运行:myReverse输入head=tail,直接返回{head, head},连接不变。


Q4:为什么不用递归?

:递归也可行,但:

  • 空间复杂度 O(n/k)(递归栈);
  • 不符合“O(1) 空间”的进阶要求;
  • 迭代解法更贴近工业实践。

八、优化思路

1. 提前计算总长度(可选)

// 先遍历一次获取 nintn=0;ListNodecur=head;while(cur!=null){n++;cur=cur.next;}// 然后只处理前 (n / k) * k 个节点
  • 优点:避免在每组都检查长度;
  • 缺点:多一次遍历,且n ≤ 5000时收益微乎其微。

2. 内联反转逻辑

myReverse逻辑直接写入主函数,减少函数调用开销(JIT 通常会优化,意义不大)。

3. 工程化增强

  • 输入校验:虽然题目保证1<=k<=n,但生产代码应检查k <= 0
  • 日志记录:调试时打印每组反转前后状态;
  • 单元测试:覆盖k=1,k=n,n%k!=0等 case。

九、数据结构与算法基础知识点回顾

1. 链表反转(核心子问题)

  • 单链表反转:维护prev,current,next
  • 区间反转:需指定起止点,并正确连接外部

2. 虚拟头节点(Sentinel Node)

  • 作用:消除头节点特殊处理
  • 命名:常称dummy,hair,guard
  • 适用场景:任何可能改变头节点的操作

3. 指针操作原则

  • 先保存:在断开指针前,保存所有需要的引用
  • 再连接:按依赖顺序更新指针
  • 画图验证:复杂操作务必画图

4. 空间复杂度意识

  • O(1) 空间:意味着不能使用递归、栈、额外数组
  • 面试重点:进阶要求常考察空间优化能力

十、面试官提问环节(模拟)

❓ 问题1:你的解法中,myReverse 函数能否改为 void?

回答
可以,但需要额外参数传递prenextGroup
当前设计让myReverse职责单一(只负责反转),主函数负责连接,符合单一职责原则,代码更清晰。


❓ 问题2:如果要求从右往左每 k 个反转(如 [1,2,3,4,5], k=2 → [1,3,4,2,5]),怎么办?

回答
这属于不同问题。可能需要:

  1. 先计算总长度n
  2. 从位置n%k+1开始分组;
  3. 或使用栈缓存前n%k个节点。
    但本题明确是“从左往右”分组。

❓ 问题3:你的算法能处理环形链表吗?

回答
不能,且题目假设链表无环。
若存在环,找tail的循环会无限执行。
实际工程中,应先用 Floyd 判环算法检测,再处理。


❓ 问题4:为什么变量叫 hair 而不是 dummy?

回答
这是 LeetCode 官方题解的命名习惯(“hair” as in “hare” from tortoise and hare algorithm)。
本质上和dummy一样,都是虚拟头节点。命名不影响逻辑,但建议使用更直观的dummyHead


十一、这道算法题在实际开发中的应用

虽然“K 个一组反转”看似理论化,但其思想在实际系统中非常有用:

1.数据分块处理

  • 大文件读取时,按固定块大小(k)处理;
  • 反转可模拟“倒序处理块内数据”的需求。

2.网络协议中的分段重组

  • TCP 分段传输后,接收端需按序重组;
  • 若协议要求每 k 个包反向确认,可用类似逻辑。

3.音频/视频缓冲区管理

  • 音频采样点存储在链表中;
  • 某些特效(如回声)需分段反转播放。

4.任务批处理调度

  • 任务队列按 k 个一批提交;
  • 若需逆序执行批次内任务,可用此算法重排。

💡核心价值:训练分治思想指针操作精度,这是系统编程的基石。


十二、相关题目推荐

掌握本题后,可挑战以下 LeetCode 题目:

题号题目关联点
206. 反转链表基础子问题
92. 反转链表 II区间反转相似技巧
24. 两两交换链表中的节点k=2 特例同类问题
143. 重排链表找中点+反转+合并综合应用
234. 回文链表反转后半段子链表操作
86. 分隔链表哑节点链表重组

建议按顺序练习,逐步构建链表操作知识体系。


十三、总结与延伸

✅ 本题核心收获

  1. 分组处理思想:将大问题分解为重复子问题(每组反转);
  2. 虚拟头节点:优雅解决头节点变更和边界问题;
  3. 区间反转技巧:通过设置正确的prev初始值,实现精准反转;
  4. O(1) 空间意识:迭代优于递归,符合工业级要求。

🔮 延伸思考

  • 双向链表如何实现?
    需额外维护prev指针,反转时同步更新,逻辑更复杂。

  • 能否并行处理各组?
    理论上可以(各组独立),但链表非随机访问,实际难以并行化。

  • 函数式解法?
    在支持不可变数据结构的语言中,需重建节点,空间开销大。

🌟 最后建议

  • 手写代码:在白板上写出主循环和反转逻辑,确保无 bug;
  • 讲清思路:面试时先说“我打算用虚拟头节点+分段反转”,再解释细节;
  • 主动测试:提出测试k=1,k=n,n=5,k=3等 case,展现全面性。

“链表题,分而治之是策略,指针操作是基本功。”
掌握本题,你就拥有了处理复杂链表变形的利器。继续前行,算法之路越走越宽!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1168595.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全检测实战核心技术:从入侵识别到构建主动威胁感知体系

一&#xff0c;网络安全漏洞 安全威胁是指所有能够对计算机网络信息系统的网络服务和网络信息的机密性&#xff0c;可用性和完整性产生阻碍&#xff0c;破坏或中断的各种因素。安全威胁可分为人为安全威胁和非人为安全威胁两大类。 1&#xff0c;网络安全漏洞威胁 漏洞分析的…

2026年网络安全学习路线+自学笔记(超详细) 自学网络安全看这一篇就够了

一、什么是网络安全 网络安全是一种综合性的概念&#xff0c;涵盖了保护计算机系统、网络基础设施和数据免受未经授权的访问、攻击、损害或盗窃的一系列措施和技术。经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”…

03. NFS服务器

NFS 服务介绍 在计算机网络存储领域&#xff0c;NFS&#xff08;Network File System&#xff0c;网络文件系统&#xff09;是一种实现不同计算机之 间文件共享的经典技术。它允许网络中的客户端计算机像访问本地文件一样&#xff0c;透明地访问远程服 务器上的文件资源&#…

Python+Vue的卫生室药店信息管理系 django Pycharm flask

收藏关注不迷路&#xff01;&#xff01;需要的小伙伴可以发链接或者截图给我 项目介绍 随着时代的发展&#xff0c;我国的医疗事业也取得了非常大的成就&#xff0c;很多大型的医院都哦以及实现了现代医疗信息的管理&#xff0c;但是很多卫士室扔采用人工手动的方式对病人和医…

Java版LeetCode热题100之「随机链表的复制」详解

Java版LeetCode热题100之「随机链表的复制」详解 本文约9200字&#xff0c;全面深入剖析 LeetCode 第138题《随机链表的复制》。涵盖题目解析、两种解法&#xff08;哈希表回溯法 & 节点拆分法&#xff09;、复杂度分析、面试高频问答、实际开发应用场景、相关题目推荐等&a…

伺服电机控制:编码器与霍尔传感器揭秘

伺服电机控制中使用编码器和霍尔传感器在原理、精度、成本和应用场景上有显著区别。以下是详细对比&#xff1a;一、霍尔传感器原理基于磁场感应&#xff1a;霍尔传感器检测永磁体&#xff08;转子&#xff09;的磁场变化&#xff0c;当转子磁极经过时&#xff0c;输出脉冲信号…

Python+Vue的超市进销存管理系统 django Pycharm flask

收藏关注不迷路&#xff01;&#xff01;需要的小伙伴可以发链接或者截图给我 项目介绍 超市进销存管理系统是针对超市运营而设计的一套综合管理系统。超市进销存管理系统旨在提高超市的运营效率和管理水平&#xff0c;传统的超市商品管理都是人工手动的方式在进行管理&#xf…

企业级靓车汽车销售网站管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

摘要 随着互联网技术的飞速发展&#xff0c;汽车销售行业逐步向数字化转型&#xff0c;传统的线下销售模式已无法满足现代消费者的需求。消费者对购车体验的便捷性、透明度和个性化服务提出了更高要求&#xff0c;而企业也需要更高效的管理工具来优化库存、客户关系和销售流程。…

(保姆级)自学网络安全超详细学习路线,从青铜到王者的进阶之路_网络安全工程师自学

算上从学校开始学习&#xff0c;已经在网安这条路上走了10年了&#xff0c;无论是以前在学校做安全研究&#xff0c;还是毕业后在百度、360从事内核安全产品和二进制漏洞攻防对抗&#xff0c;我都深知学习方法的重要性。没有一条好的学习路径和好的学习方法&#xff0c;往往只会…

vue基于Python图书销售数据爬取及可视化系统的设计与实现 flask django Pycharm

收藏关注不迷路&#xff01;&#xff01;需要的小伙伴可以发链接或者截图给我 项目介绍 随着互联网技术的飞速发展和普及&#xff0c;人们的消费习惯和购物方式也在发生深刻的变化。在这样的背景下&#xff0c;图书销售数据爬取及可视化系统应运而生。与传统的实体书店相比&…

Java Web 植物健康系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 背景相关 随着城市化进程加快和环境污染问题日益突出&#xff0c;植物健康管理成为生态保护与农业可持续发展的重要课题。传统植物健康监测依赖人工观察和实验室分析&#xff0c;效率低下且成本高昂&#xff0c;难以满足现代精准农业的需求。信息化技术的快速发展为植物健…

Python+Vue的全域智慧旅游系统的设计与实现 django Pycharm flask

收藏关注不迷路&#xff01;&#xff01;需要的小伙伴可以发链接或者截图给我 项目介绍 随着时代的发展&#xff0c;越来越多的人喜欢旅游&#xff0c;但是很多时候人们并不知道去哪里旅游且购买门票和预订也需要到地方后才可以购买和预订&#xff0c;为了方便用户更加方便的预…

网络安全从0到1,保姆级学习路线(2026)

网络安全从0到1&#xff0c;保姆级学习路线&#xff08;2026&#xff09; 一、前言&#xff1a;网络安全为什么值得学&#xff1f; 在数字化浪潮下&#xff0c;网络攻击事件频发&#xff08;数据泄露、勒索病毒、APT 攻击等&#xff09;&#xff0c;企业对安全人才的需求缺口持…

网络信息安全工程师 应该怎样入门?需要有什么知识基础?零基础入门到精通,收藏这一篇就够了

网络安全工程师是一个很广泛的职业概称&#xff0c;只要是网络安全相关的从业者&#xff0c;都算是网络安全工程师。网络安全相关岗位很多&#xff0c;有信息安全工程师、渗透测试工程师、应急响应安全工程师、逆向安全工程师、溯源取证安全工程师、安全架构师、恶意软件安全分…

2026 数据库国产化预测:从替代到引领的格局重构与规模爆发

如果说过去五年数据库国产化是 “破冰突围”&#xff0c;那么 2026 年将正式迈入 “深水区攻坚”。作为数字经济的 “地基”&#xff0c;数据库的自主可控程度直接决定了国家数字战略的安全底线。在信创 2.0 战略纵深推进与 AI、云原生技术浪潮的双重驱动下&#xff0c;国产数据…

入门网络安全工程师要学习哪些内容【2026年寒假最新学习计划】

大家都知道网络安全行业很火&#xff0c;这个行业因为国家政策趋势正在大力发展&#xff0c;大有可为!但很多人对网络安全工程师还是不了解&#xff0c;不知道网络安全工程师需要学什么?知了堂小编总结出以下要点。 网络安全工程师是一个概称&#xff0c;学习的东西很多&…

Python+Vue的 青岛健力士商贸有限公司食品质量管理平台 django Pycharm flask

收藏关注不迷路&#xff01;&#xff01;需要的小伙伴可以发链接或者截图给我 项目介绍 随着我国经济的不断发展&#xff0c;我国的主要矛盾已经从人民日益增长的物质文化需要同落后的社会生产之间的矛盾转化为人民日益增长的美好生活需要和不平衡不充分发展之间的矛盾&#xf…

Nginx 配置参数化实践:通过 Docker Run 传递参数实现动态代理配置

概述 在微服务架构中&#xff0c;前端应用通常需要代理多个后端服务的 API 请求。传统的做法是为每个环境&#xff08;开发、测试、生产&#xff09;构建不同的镜像&#xff0c;这会导致镜像管理复杂、部署效率低下。本文将介绍如何通过 Nginx 配置参数化&#xff0c;结合 Doc…

救命!挖到宝藏资源!网安工程师必备 8 款黑客工具,安装包直接领,实战神器拉满!

网络安全工程师在维护和保护信息系统的安全性方面扮演着至关重要的角色。为了有效地完成这一任务&#xff0c;他们需要掌握并使用多种工具。本文将详细介绍八款网络安全工程师必备的工具&#xff0c;包括Snort、Wireshark、Nmap、Metasploit、Nessus、OpenVAS、Firewall和Proxy…

Linux如何查看网关?

在Linux网络配置与故障排查中&#xff0c;查看网关地址是一项基础且关键的操作&#xff0c;直接关系到服务器或主机能否正常访问外网、实现跨网段通信。那么Linux如何查看网关?以下是具体内容介绍。1、使用route命令查看路由表route -n是最常用的查看路由表的命令之一&#xf…