当前位置: 首页 > news >正文

力扣hot100-234.回文链表-快慢指针与反转详解

234. 回文链表:快慢指针与反转详解

题目链接:234. 回文链表


算法思路

链表 / 快慢指针 / 反转后半段 / 双指针比较

回文的含义是:从左往右读,与从右往左读完全一样。

例如:

1 -> 2 -> 2 -> 1

从两端向中间看:

第 1 个节点和倒数第 1 个节点:1 == 1 第 2 个节点和倒数第 2 个节点:2 == 2

因此它是回文链表。

本题的核心流程是:

找中点 -> 奇数长度时跳过中点 -> 反转后半段 -> 从两端向中间比较

1. 为什么链表需要先反转后半段

如果是数组,可以直接通过下标从两端读取:

nums[left]nums[right]

但单链表只能沿着next从前往后走:

1 -> 2 -> 2 -> 1

虽然可以从第一个节点走到最后一个节点,却不能从最后一个节点走回前一个节点。

也就是说,链表没有办法像数组一样直接比较:

第一个节点 与 最后一个节点 第二个节点 与 倒数第二个节点

解决方式是把后半段反转。

例如:

原链表:1 -> 2 -> 2 -> 1 后半段:2 -> 1 反转后:1 -> 2

现在可以同时从前向后读取两段:

左半段:1 -> 2 右半段:1 -> 2

原本的“从两端比较”,就转换成了“两个指针从前向后比较”。


2. 如何找到中点:快慢指针

定义两个指针:

ListNodeslow=head;ListNodefast=head;

移动规则:

slow 每轮走 1 步 fast 每轮走 2 步

因此:

fast 到达末尾时,slow 正好到达链表中间。

代码:

while(fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;}

循环条件中的两个判断含义分别是:

fast != null:fast 当前仍在链表内。 fast.next != null:fast 还能再走两步,不会访问空指针。

3. 偶数长度时,slow在哪里

假设链表为:

1 -> 2 -> 2 -> 1

初始:

1 -> 2 -> 2 -> 1 ^ slow、fast

第 1 轮后:

1 -> 2 -> 2 -> 1 ^ ^ slow fast

第 2 轮后:

1 -> 2 -> 2 -> 1 ^ slow fast = null

此时slow指向后半段的第一个节点:

1 -> 2 | 2 -> 1 ^ slow

所以偶数长度时,直接从slow开始反转后半段即可。


4. 奇数长度时,为什么要跳过中点

假设链表为:

1 -> 2 -> 3 -> 2 -> 1

快慢指针结束时:

1 -> 2 -> 3 -> 2 -> 1 ^ ^ slow fast

此时:

slow 指向正中间节点 3 fast 不为 null,且停在最后一个节点 1

中间节点3没有需要比较的配对节点:

1 <-> 1 2 <-> 2 3 不需要配对

因此应跳过它:

if(fast!=null){slow=slow.next;}

跳过后:

1 -> 2 -> 3 | 2 -> 1 ^ slow

之后只反转2 -> 1,让它与左半段1 -> 2对齐比较。

为什么用fast != null判断奇数长度?

偶数长度:fast 每次刚好跨过两个节点,最终走到 null。 奇数长度:最后会剩一个节点无法再走两步,fast 停在最后一个节点,不是 null。

5. 完整推演:1 -> 2 -> 3 -> 2 -> 1

第一步:找到中点并跳过它

快慢指针结束时:

1 -> 2 -> 3 -> 2 -> 1 ^ slow

因为fast != null,这是奇数长度,跳过中间节点3

1 -> 2 -> 3 -> 2 -> 1 ^ slow

第二步:反转后半段

slow开始的后半段是:

2 -> 1 -> null

反转后,得到:

1 -> 2 -> null

它代表原链表从右到左读到的节点值。

第三步:逐个比较

此时:

left: 1 -> 2 -> 3 -> ... right: 1 -> 2 -> null

比较过程:

left 的 1 == right 的 1,继续。 left 的 2 == right 的 2,继续。 right 到达 null,比较完成。

所以该链表是回文链表。


6. Java 代码完整注释

classSolution{publicbooleanisPalindrome(ListNodehead){// 空链表或只有一个节点时,从正反两个方向读都相同。if(head==null||head.next==null){returntrue;}// slow 每轮走一步,fast 每轮走两步。// fast 到末尾时,slow 会到达链表中间位置。ListNodeslow=head;ListNodefast=head;while(fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;}// fast 不为 null,说明节点数为奇数。// slow 此时指向正中间节点;中点无需比较,直接跳过。if(fast!=null){slow=slow.next;}// 反转后半段。// right 的遍历顺序等价于从原链表尾部向中间读取。ListNoderight=reverse(slow);// left 从原链表头部开始读取。ListNodeleft=head;// 后半段长度不会超过前半段。// 右半段全部匹配,就说明整条链表是回文。while(right!=null){if(left.val!=right.val){returnfalse;}left=left.next;right=right.next;}returntrue;}privateListNodereverse(ListNodehead){// pre 指向已经反转完成部分的头节点。ListNodepre=null;// cur 指向当前需要反转的节点。ListNodecur=head;while(cur!=null){// 保存原来的下一个节点。// 因为下一步会覆盖 cur.next,必须先保住后续链表。ListNodenext=cur.next;// 让当前节点指向前一个节点,完成当前节点的反转。cur.next=pre;// 移动指针,继续反转原链表中的下一个节点。pre=cur;cur=next;}// pre 指向反转后链表的新头节点。returnpre;}}

7. 为什么只比较到right == null

right是反转后的后半段。

对于偶数长度:

左半段长度 == 右半段长度

对于奇数长度,跳过中点后:

左侧可比较节点数 == 右半段长度

所以无论奇偶,只要右半段的每个节点都与左侧对应节点相同,就已经完成了所有必要比较:

while(right!=null)

不需要等待left走到null;奇数长度时,left还会多经过中间节点以及后半段,而它们都不应该重复参与比较。


8. 这段代码会改变原链表吗

会,且改变发生在这一步:

ListNoderight=reverse(slow);

它会把原链表的后半段原地反转。

LeetCode 这题通常只要求返回是否回文,允许这种做法,因为题目不会在方法返回后继续检查原链表的结构。

如果在实际业务代码中,后续还要使用原链表的原始顺序,应当在比较结束后:

再次反转 right,把后半段恢复。

这不会改变时间复杂度,仍然是O(n)


9. 复杂度

假设链表有n个节点。

时间复杂度:

找中点:O(n) 反转后半段:O(n) 比较两半:O(n) 总计:O(n)

虽然进行了多个阶段,但它们都是对链表进行常数次遍历,因此总时间复杂度仍是线性的。

额外空间复杂度:

O(1)

只使用了有限个指针变量,没有使用数组、栈或HashSet

一句话记忆:

快慢指针找中点;奇数长度跳过中点;反转后半段;用左右指针从前向后逐个比较。
http://www.jsqmd.com/news/1302479/

相关文章:

  • 电路题目
  • 异步 Rust 的精进之路:从 Future trait 到自定义 Runtime 的能力阶梯图
  • mlx-community/AREX-Turbo-6bit完全解析:从模型架构到核心功能的终极指南
  • 滴图开放平台企业级 LBS 服务全解析:技术能力、场景方案与落地价值
  • Agent Skills:把团队里“只会做一遍“的经验,变成 Agent 能反复调用的能力包
  • Norm高级用法:使用selection/2轻松实现数据字段的可选与必选控制
  • 花都区粤菜餐厅哪家味道好?:【锦堂春想】唇齿留香 - 17728181569
  • 限行天气联动 API 常见错误与排错指南:从 400 到 500 的异常处理
  • 音频识别转文字免费版额度够日常使用吗2026实测多款工具告诉你答案
  • 2026欧美绷带裙ODM选厂痛点深度解析 绷带裤绷带连衣裙靠谱合作厂家指南 - 甄选测评馆
  • 白番茄光感透肌面膜哪家靠谱:【蜜妙诗】正品正宗 - 17728181569
  • webtrees协作功能详解:多人共同编辑家谱的最佳实践
  • 2026年7月配音网站实测:8款TTS工具生成速度/音质/字幕准确率大比拼
  • ZenlessZoneZero-OneDragon:绝区零全自动游戏体验终极解决方案
  • GEO策略:哪些动作值得加码,哪些操作应当立即叫停?
  • BilibiliDown音频提取终极指南:从B站视频中提取高质量音乐的3种方法
  • 提升视频生成质量:LTX-2.3 Motion Enhancer-n4w的10个专业提示
  • 抖音内容高效管理方案:douyin-downloader全面解析与实战指南
  • 靶向肝实质/非实质细胞的AAV血清型与启动子“组合拳”全攻略
  • 远程控制软件哪个好用 远程控制软件推荐无界趣连2.0
  • 如何高效使用Ryujinx模拟器:完整实用指南让你在PC上畅玩Switch游戏
  • 【锦堂春想】绝佳口碑 - 17328623207
  • Mage2Gen核心功能揭秘:从控制器到插件的10大实用Snippet
  • 花都区粤菜餐厅哪家性价比高?:【锦堂春想】划算省心 - 18102756859
  • 2026年国内专业的热处理炉温跟踪仪厂家联系电话 - 品牌排行榜
  • 双目相机、SLAM、极线几何与相机标定总结
  • 3步掌握KeymouseGo:免费开源鼠标键盘录制自动化终极指南
  • GLM 5.2 Token经济体系解析:从512K上下文到成本优化策略
  • 31号总结
  • 2026 年新消息:龙口诚信的路面混凝土切割公司选哪家,老小区修路花2万,老师傅偷偷用这法子省了大半成本?-盛达水钻切割 - 行业甄选官