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

生活中的回文现象

在日常生活中,回文无处不在。比如"上海自来水来自海上"、"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. Sealos AI Proxy 发布!一个平台调用所有大模型,再也不用到处找 API 了

    你是一位开发者,你需要调用各类 AI 模型,每次调用模型,都要在不同的平台间反复横跳,你大概会遇到以下问题: 获取 API Key 流程繁琐:需访问多个厂商的官网,查阅各自的使用文档,并按照规定的步骤 ...

  2. 获取Map中选择的要素

    <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...

  3. uniapp安卓在线更新版本

    实现逻辑 通过获取线上的版本号和app的版本号进行对比 查看是不是最新版 - app版本号小于线上版本号则不是最新版 提示更新 模拟检测更新请求 起一个服务,也就是检测更新的接口 返回值为最新版本号和 ...

  4. uni-app小程序(快手、抖音)getCurrentPages使用坑位记录

    前情 uni-app是我比较喜欢的跨平台框架,它能开发小程序/H5/APP(安卓/iOS),重要的是对前端开发友好,自带的IDE让开发体验也挺棒的,公司项目就是主推uni-app. 坑位 最近在做一个 ...

  5. orangepi zero3开启指定频段WiFi热点的指令

    步骤 通过 -c 命令即可指定wifi频段,避免和其他wifi的频段撞在一起. 例如下面这条命令创建了一个频段为40,WiFi名为zero3,网段为192.168.12.0/24的WiFi热点 sud ...

  6. 在PlatformIO IDE中对ESP32的CPU主频等进行配置

    前言 rt,有一天开发中需要尽可能发挥ESP32的全部性能,提高主频自然是首选,在Arduino IDE中修改主频很方便,但在PlatformIO IDE中修改主频的方法网上说的却很少,今天就总结一下 ...

  7. HTML 面试题

    .code { background-color: rgba(246, 246, 246, 1); color: rgba(232, 62, 140, 1) } DOCTYPE的作用? DOCTYPE ...

  8. Flutter showModalBottomSheet改变高度

    showModalBottomSheet改变高度 将isScrollControlled设置为true,此时弹窗会全屏展示,再返回一个带高度的SizedBox,就可以指定弹窗的高度了 showModa ...

  9. 视频监控推流助手/极低延迟/支持N路批量多线程推流/264和265推流/监控转网页

    一.前言说明 搞视频监控开发除了基本的拉流以外,还有个需求是推流,需要将拉到的流重新推流到流媒体服务器,让流媒体服务做转发和负载均衡,这样其他地方只需要问流媒体服务器要视频流即可.为什么拉了又重新推呢 ...

  10. FFmpeg中的色彩空间与像素格式3-像素格式

    FFmpeg 中的色彩与像素系列文章如下: [1]. FFmpeg中的色彩空间与像素格式1-色彩空间基础 [2]. FFmpeg中的色彩空间与像素格式2-RGB/YUV色彩空间 [3]. FFmpeg ...