从生活场景到回文链表:探索对称性检测

生活中的回文现象

在日常生活中,回文无处不在。比如"上海自来水来自海上"、"12321"这样正着读和倒着读都一样的字符串或数字,就是回文。把这个概念扩展到链表,我们就得到了今天要讨论的回文链表问题:一个链表从前往后读和从后往前读的结果是否相同。

问题描述

LeetCode第234题"回文链表"要求:给你一个单链表的头节点 head,请判断该链表是否为回文链表。

例如:

输入:1 → 2 → 2 → 1
输出:true 输入:1 → 2 → 3 → 2 → 1
输出:true 输入:1 → 2 → 3 → 3 → 1
输出:false

基础知识准备

这道题的核心是利用我们之前学过的"反转链表"。如果不熟悉链表反转,建议先复习上一篇文章。记住,链表反转是一块基石,在这里我们要用它来解决更复杂的问题。

直观解法:转换为数组

最简单的想法是:把链表转换成数组,然后用双指针从两端向中间移动比较。这就像把一摞扑克牌摊开在桌上,从两端开始对比每张牌是否相同。

数组法实现

public boolean isPalindrome(ListNode head) {
List<Integer> vals = new ArrayList<>(); // 将链表值复制到数组中
ListNode current = head;
while (current != null) {
vals.add(current.val);
current = current.next;
} // 使用双指针判断是否回文
int left = 0, right = vals.size() - 1;
while (left < right) {
if (!vals.get(left).equals(vals.get(right))) {
return false;
}
left++;
right--;
} return true;
}

优化解法:反转后半部分

仔细思考,我们其实不需要额外的数组。可以用这个巧妙的方法:

  1. 找到链表中点
  2. 反转后半部分
  3. 比较前后两半是否相同
  4. (可选)恢复链表原状

这就像把一叠纸牌分成两半,把后半部分倒过来,然后一张张对比。

寻找中点:快慢指针法

想象两个人在跑道上跑步,一个速度是另一个的两倍。当快跑者跑到终点时,慢跑者正好在中点!

详细代码实现

public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
} // 第1步:找到中点
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
} // 第2步:反转后半部分
ListNode secondHalf = reverseList(slow.next); // 第3步:比较两半是否相同
ListNode firstHalf = head;
ListNode temp = secondHalf; // 保存开始位置,用于之后恢复
boolean result = true;
while (secondHalf != null) {
if (firstHalf.val != secondHalf.val) {
result = false;
break;
}
firstHalf = firstHalf.next;
secondHalf = secondHalf.next;
} // 第4步:恢复链表(可选)
slow.next = reverseList(temp); return result;
} // 链表反转函数(使用我们之前学过的方法)
private ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}

图解过程

以1→2→3→2→1为例:

1) 初始状态:
1 → 2 → 3 → 2 → 1 2) 找到中点:
1 → 2 → [3] → 2 → 1
slow指向3 3) 反转后半部分:
1 → 2 → 3 ← 2 ← 1 4) 比较两半:
(1 → 2) 和 (1 → 2) 比较 5) 恢复原状:
1 → 2 → 3 → 2 → 1

复杂度分析

空间优化解法:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1),只使用几个指针
  • 优点:空间效率高,且思路优雅
  • 缺点:修改了原链表结构(虽然最后恢复了)

重要思维方式总结

  1. 问题转化:将回文判断转化为对称性比较

  2. 空间优化思维

    • 不用额外数组存储
    • 利用原有空间进行操作
  3. 分步思想

    • 找中点(快慢指针)
    • 反转后半段(链表反转)
    • 对比(双指针)
    • 恢复(再次反转)
  4. 边界处理

    • 空链表
    • 单节点链表
    • 偶数/奇数长度的处理

实用技巧总结

解决类似问题的关键点:

  1. 熟练掌握基础操作(如链表反转)
  2. 善用快慢指针找中点
  3. 考虑空间优化的可能性
  4. 注意保护原始数据结构

相关的思维训练:

  • 回文数判断
  • 回文子串问题
  • 链表中点问题
  • 链表反转的各种变体

小结

回文链表问题是一个很好的例子,展示了如何将基础算法(如链表反转、快慢指针)组合起来解决更复杂的问题。它教会我们:

  1. 基础算法的重要性
  2. 空间优化的思维方式
  3. 问题分解的方法
  4. 代码的优雅性

下次遇到类似的对称性判断问题,不要急着用额外空间,想想是否可以通过改变数据结构本身来解决问题!


作者:忍者算法

公众号:忍者算法

我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~

【忍者算法】从生活场景到回文链表:探索对称性检测|LeetCode 234 回文链表的更多相关文章

  1. Leetcode 234. 回文链表(进阶)

    1.题目描述 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O ...

  2. [LeetCode] 234. 回文链表 ☆(翻转链表)

    描述 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2输出: false示例 2: 输入: 1->2->2->1输出: true 进阶:你能否用 O(n) 时间复杂 ...

  3. leetcode 234 回文链表 Palindrome Linked List

    要求用O(n)时间,和O(1)空间,因此思路是用本身链表进行判断,既然考虑回文,本方法思想是先遍历一次求链表长度,然后翻转前半部分链表:然后同时对前半部分链表和后半部分链表遍历,来判断对应节点的值是否 ...

  4. Java实现 LeetCode 234 回文链表

    234. 回文链表 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否 ...

  5. LeetCode 234——回文链表

    1. 题目 请判断一个链表是否为回文链表. 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true 进阶: 你能否用 O( ...

  6. LeetCode 234. 回文链表

    class Solution { public: bool isPalindrome(ListNode* head) { deque<int> d1, d2; ListNode* p = ...

  7. Leetcode:234 回文链表

    leetcode:234 回文链表 关键点:请判断一个链表是否为回文链表.示例 1:输入: 1->2输出: false示例 2:输入: 1->2->2->1输出: true. ...

  8. 算法:Manacher,给定一个字符串str,返回str中最长回文子串的长度。

    [题目] 给定一个字符串str,返回str中最长回文子串的长度 [举例] str="123", 1 str="abc1234321ab" 7 [暴力破解] 从左 ...

  9. LeetCode 5回文数

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...

  10. HDU - 5157 :Harry and magic string (回文树,求多少对不相交的回文串)

    Sample Input aca aaaa Sample Output 3 15 题意: 多组输入,每次给定字符串S(|S|<1e5),求多少对不相交的回文串. 思路:可以用回文树求出以每个位置 ...

随机推荐

  1. Blazor 组件库 BootstrapBlazor 中Button组件介绍

    组件介绍 按钮组件,应该是最基础的组件之一了.感觉没什么可介绍的,但是BootstrapBlazor的按钮,还是有很多不错的特性. 首先是最基础的,boostrap5的按钮样式: 代码如下: < ...

  2. 2.3k Star!强得不像开源的问卷调研平台

    产品:咱们的新功能上线了,得问问用户的意见,做个调研问卷吧! 运营:对啊,用户意见很重要,我们要认真听取反馈! 领导:问卷别搞得像考试.我们要的是真实的声音,而不是让用户头疼的题目. 程序员:收到! ...

  3. OAuth2 当前登录用户修改

    1.业务说明 有些情况下,我们希望用户登录后,可以修改用户的某些信息,比如修改当前的公司信息. 2.实现方法 @Resource TokenStore tokenStore; public JsonR ...

  4. Vue.js 其他指令

    1.ref标识 通过给HTML标签或者组件标签设定ref属性,根据他的属性值来访问这个HTML元素或者组件 语法:this.$refs.属性值 //为p标签设置ref属性 <div id=&qu ...

  5. 怎么实时更新echarts图标数据?

    function getData(){ var request . nem XPHLHttpRequest () ; request . open("get",'http://lo ...

  6. ecognition server注意事项

    1.4002端口是节点管理界面,默认密码admin. 2.8184端口是任务管理界面. 3.节点在线状态下,查看提交的影像矢量路径是否正确. 4.看服务器读取各个文件是否有误. 5.用develope ...

  7. 【VMware VCF】管理 VCF 环境中组件的密码策略。

    使用 SDDC Manager 中的"密码管理"功能可以统一管理 VCF 环境中组件的用户密码,比如更新(Update).轮换(Rotate)以及修复(Remediate)组件的密 ...

  8. Ant Design Pro项目ProTable怎么实现单元格合并效果

    前情 公司有经常需要做一些后台管理页面,我们选择了Ant Design Pro,它是基于 Ant Design 和 umi 的封装的一整套企业级中后台前端/设计解决方案. 产品效果图 最新接到的一个后 ...

  9. 【Amadeus原创】华为一键强制关闭后台应用的终极解决方法

    华为手机速度是快,用起来很顺手,但是最让人头疼的,就是紧急情况开会,我音乐关不了. 上划把全部应用删掉,也没用. 经过一阵子摸索,发现终极办法: 1, 打开华为自带的 手机助手- 应用启动管理 2, ...

  10. 禅道bug增加自定义字段

    禅道版本 18.9 需求 给禅道的bug模块,增加自定义字段. 目前主要增加"发现阶段"."所属环境"."出现频率" 增加bug的类型 在b ...