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

【力扣100题】10.回文链表(C++ 解法)

一、题目描述

给定一个单链表的头节点head,判断该链表是否为回文链表。

示例

输入:head = [1,2,2,1] 输出:true 输入:head = [1,2] 输出:false

回文定义

简单来说,就是正着读和倒着读都一样


二、核心思路

关键观察

判断回文,只需要比较前半部分和后半部分是否对称

思路:找中点 → 翻转 → 对比

原链表: 1 -> 2 -> 2 -> 1 ↑ slow(中点) 步骤1:快慢指针找中点 - slow 走 1 步,fast 走 2 步 - fast 到尾时,slow 刚好在中点 步骤2:翻转后半部分 - 后半部分 2 -> 1 反转成 1 -> 2 步骤3:逐节点比较值 - 前半部分:1 -> 2 - 后半部分:1 -> 2 - 逐节点比较 val,相等则继续

三、代码实现

方法:快慢指针 + 反转(进阶最优解)✅

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */classSolution{public:boolisPalindrome(ListNode*head){// ========== 步骤1:快慢指针找中点 ==========ListNode dummy=ListNode(0,head);// 虚拟头节点ListNode*slow=&dummy;ListNode*fast=&dummy;while(fast&&fast->next){slow=slow->next;// slow 走 1 步fast=fast->next->next;// fast 走 2 步}// ========== 步骤2:翻转后半部分 ==========fast=slow->next;// fast 指向后半部分开头slow->next=nullptr;// 断开链表ListNode*pre=nullptr;while(fast){ListNode*cur=fast->next;// 保存下一个fast->next=pre;// 反转pre=fast;// 前进fast=cur;// 前进}// ========== 步骤3:比较前后两部分 ==========while(pre){// pre 是反转后的后半部分if(head->val!=pre->val)// 比较节点的值!returnfalse;head=head->next;pre=pre->next;}returntrue;}};

复杂度分析

复杂度说明
时间O(n)遍历链表常数次
空间O(1) ✅只用了几个指针

四、图解全过程

示例:[1, 2, 2, 1]

原始链表:

1 -> 2 -> 2 -> 1 -> nullptr

步骤1:找中点

dummy -> 1 -> 2 -> 2 -> 1 -> nullptr ↑ ↑ slow fast 循环后: dummy -> 1 -> 2 -> 2 -> 1 -> nullptr ↑ ↑ slow fast(null)

步骤2:翻转后半部分

前半部分:1 -> 2 后半部分:2 -> 1 (original) 反转后后半:1 -> 2 链表变成: dummy -> 1 -> 2 -> nullptr ↑ slow 1 -> 2 (反转后的后半) ↑ pre

步骤3:比较

head(1) vs pre(1) ✓ head(2) vs pre(2) ✓ pre = nullptr,结束 返回 true ✓

示例:[1, 2](非回文)

比较:1 vs 2,不相等 返回 false ✓

五、为什么需要虚拟头节点?

ListNode dummy=ListNode(0,head);ListNode*slow=&dummy;ListNode*fast=&dummy;

使用dummy是为了统一处理,避免讨论head为空或只有一个节点的边界情况。

不用 dummy用 dummy
需要额外判断 head自动处理
代码更复杂代码简洁

六、其他解法(不推荐)

方法2:数组比较(不满足进阶要求)

boolisPalindrome_array(ListNode*head){vector<int>vals;while(head){vals.push_back(head->val);head=head->next;}// 双指针比较intleft=0,right=vals.size()-1;while(left<right){if(vals[left++]!=vals[right--])returnfalse;}returntrue;}
复杂度
时间O(n)
空间O(n) ❌

七、方法对比

方法时间空间推荐度
快慢指针 + 反转O(n)O(1) ✅⭐⭐⭐最优
数组 + 双指针O(n)O(n)⭐⭐ 简单但空间不优

八、完整测试代码

#include<iostream>usingnamespacestd;structListNode{intval;ListNode*next;ListNode():val(0),next(nullptr){}ListNode(intx):val(x),next(nullptr){}ListNode(intx,ListNode*next):val(x),next(next){}};classSolution{public:boolisPalindrome(ListNode*head){// 步骤1:找中点ListNode dummy=ListNode(0,head);ListNode*slow=&dummy;ListNode*fast=&dummy;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}// 步骤2:翻转后半部分fast=slow->next;slow->next=nullptr;ListNode*pre=nullptr;while(fast){ListNode*cur=fast->next;fast->next=pre;pre=fast;fast=cur;}// 步骤3:比较值while(pre){if(head->val!=pre->val)returnfalse;head=head->next;pre=pre->next;}returntrue;}};// 辅助函数:创建链表ListNode*createList(vector<int>vals){if(vals.empty())returnnullptr;ListNode*head=newListNode(vals[0]);ListNode*curr=head;for(inti=1;i<vals.size();i++){curr->next=newListNode(vals[i]);curr=curr->next;}returnhead;}intmain(){Solution sol;// 测试1:回文ListNode*head1=createList({1,2,2,1});cout<<"1,2,2,1 是回文? "<<(sol.isPalindrome(head1)?"true":"false")<<endl;// 测试2:非回文ListNode*head2=createList({1,2});cout<<"1,2 是回文? "<<(sol.isPalindrome(head2)?"true":"false")<<endl;// 测试3:单节点ListNode*head3=createList({1});cout<<"1 是回文? "<<(sol.isPalindrome(head3)?"true":"false")<<endl;return0;}

输出:

1,2,2,1 是回文? true 1,2 是回文? false 1 是回文? true

九、总结

步骤操作关键点
1快慢指针找中点fast 走 2 步,slow 走 1 步
2反转后半部分迭代法反转
3比较节点值必须是head->val != pre->val,不是指针比较!
http://www.jsqmd.com/news/568138/

相关文章:

  • CBconvert:漫画爱好者的终极格式转换解决方案,支持10+格式互转
  • 描述 Linux 系统中 crontab 的工作原理,并给出一个每天凌晨 3 点执行备份脚本的 crontab 配置例子。
  • Phi-4-mini-reasoning vLLM监控告警:GPU显存溢出与请求超时自动通知
  • k8s网络Cilium5 - 小镇
  • Azure OpenAI服务升级踩坑记:从OpenAI库v0.27.0到v1.x,手把手解决LangChain中的404报错
  • Full Page Screen Capture:一键搞定超长网页截图的终极解决方案
  • 探索基于模型预测算法的含储能微网双层能量管理模型代码
  • 告别重复编码:用快马ai自动生成c语言基础工具模块提升效率
  • League-Toolkit英雄联盟智能工具完全攻略:从入门到精通
  • C++ Move 构造函数性能优化
  • Meld代码对比工具:安装配置与高效使用指南
  • SEO_ 为什么你的SEO没效果?关键原因与解决办法
  • YOLO-Master 与 YOLO 开始
  • Blender中GLB坐标转化及导出
  • 递归现象学方法论:自指悬置与本质直观的递归扩展【世毫九实验室原创理论】
  • 开箱即用!Qwen-Image-2512-SDNQ Web服务快速体验指南
  • 告别ALV展示难题:一个自研ABAP类搞定所有复杂内表(含嵌套表和结构)
  • 5大理由告诉你为什么Argos Translate是离线翻译的最佳Python解决方案 [特殊字符]
  • Godot-MCP:游戏开发智能协作框架的技术实现与架构解析
  • 通义千问3-Reranker-0.6B入门必看:32K长上下文+多语言嵌入重排全解析
  • 如何高效使用draw.io桌面版:完整实用指南
  • Cumulocity Arduino库:嵌入式MQTT轻量接入方案
  • 别再折腾OBS了!用Node.js+FFmpeg+node-media-server,5分钟搞定Windows本地直播推流服务器
  • 新手零压力入门,快马ai带你三步搞定nodejs环境配置
  • 美团LongCat团队:560亿参数AI模型实现高难度数学证明能力突破
  • App 上架流程:App Store 国内各大市场
  • 【OpenClaw】创建一个每日热点新闻 Skill
  • C++ 智能指针的常见误用与性能影响
  • 别再只盯着Attention图了!用LRP+梯度融合,手把手教你给Vision Transformer做更准的“CT扫描”
  • Linux 内核中的虚拟文件系统:从抽象到实现