每日算法练习:LeetCode 125. 验证回文串 ✅

大家好,我是你们的算法小伙伴。今天我们来练习一道字符串处理的经典基础题 ------LeetCode 125. 验证回文串。这道题考察字符串的预处理和双指针的应用,难度适中,是面试中常见的字符串类入门题目,既能巩固基础语法,也能锻炼解题思路的严谨性。

题目描述

给定一个字符串s ,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

示例 1:

复制代码
输入:s = "A man, a plan, a canal: Panama"

输出:true

解释:"amanaplanacanalpanama" 是回文串。

示例 2:

复制代码
输入:s = "race a car"

输出:false

解释:"raceacar" 不是回文串。

示例 3:

复制代码
输入:s = " "

输出:true

解释:空字符串是回文串。

提示:

1 <= s.length <= 2 * 10⁵

字符串 s 由 ASCII 字符组成

解题思路

核心定义拆解

回文串的核心定义:正读和反读完全相同的字符串。本题有两个关键限制:

  1. 只考虑 字母和数字字符,忽略标点、空格等其他字符;

  2. 忽略字母的大小写(例如 'A' 和 'a' 视为相同字符)。

解题的核心思路的是:先对字符串进行预处理,过滤无效字符并统一大小写,再验证处理后的字符串是否为回文。

方法一:预处理 + 双指针

**思路:**先遍历原字符串,过滤掉非字母数字的字符,同时将所有字母转为统一大小写(小写或大写),得到一个纯字母数字的字符串;再用双指针从字符串两端向中间遍历,逐一对比对应位置的字符,若所有字符都相等,则为回文串。

方法二:原地双指针

**思路:**无需额外存储预处理后的字符串,直接在原字符串上使用双指针。左指针从头部、右指针从尾部开始,遇到非字母数字的字符则跳过,遇到字母则统一转为小写(或大写)后对比,直至指针相遇。该方法无需额外空间,效率更高。

代码实现

方法一:预处理 + 双指针

java 复制代码
class Solution {
    public boolean isPalindrome(String s) {
        // 1. 预处理:过滤非字母数字字符,统一转为小写
        StringBuilder filtered = new StringBuilder();
        for (char c : s.toCharArray()) {
            // 判断当前字符是否为字母或数字
            if (Character.isLetterOrDigit(c)) {
                filtered.append(Character.toLowerCase(c));
            }
        }
        // 2. 双指针验证回文
        int left = 0;
        int right = filtered.length() - 1;
        while (left < right) {
            // 对比左右指针指向的字符
            if (filtered.charAt(left) != filtered.charAt(right)) {
                return false;
            }
            left++;  // 左指针右移
            right--; // 右指针左移
        }
        return true;
    }
}

方法二:原地双指针(空间优化)

java 复制代码
class Solution {
    public boolean isPalindrome(String s) {
        int left = 0;
        int right = s.length() - 1;
        while (left < right) {
            // 左指针跳过非字母数字字符
            while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
                left++;
            }
            // 右指针跳过非字母数字字符
            while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
                right--;
            }
            // 统一转为小写后对比
            if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

代码详解

一、预处理 + 双指针

  1. StringBuilder filtered = new StringBuilder();:用于存储预处理后的纯字母数字字符串,避免字符串拼接的性能损耗(String 不可变,拼接会产生新对象)。

  2. Character.isLetterOrDigit(c):判断字符c 是否为字母或数字,精准过滤标点、空格等无效字符。

  3. Character.toLowerCase(c):将字母转为小写,消除大小写差异(例如 'A' 和 'a' 统一为 'a')。

  4. 双指针遍历:左指针从 0 开始(字符串头部),右指针从 filtered.length() - 1 开始(字符串尾部),每次对比后指针向中间移动,若出现字符不相等则直接返回 false,直至指针相遇。

示例 1 模拟:

输入 "A man, a plan, a canal: Panama"

预处理后 → "amanaplanacanalpanama",双指针从两端对比,所有字符均相等,返回 true。

二、原地双指针

  1. 跳过无效字符:两个内层 while 循环分别控制左、右指针,遇到非字母数字字符则跳过,直至找到有效字符或指针相遇。

  2. 字符对比:找到有效字符后,统一转为小写对比,若不相等则返回 false;若相等则指针继续向中间移动。

  3. 优势:无需额外存储字符串,节省空间,尤其适合处理大规模字符串(如提示中长度达 2*10⁵ 的字符串)。

示例 2 模拟:

输入 "race a car"

原地遍历:左指针找到 'r',右指针找到 'r' → 相等;继续移动,左指针找到 'a',右指针找到 'a' → 相等;再移动,左指针找到 'c',右指针找到 'c' → 相等;继续移动,左指针找到 'e',右指针找到 'a' → 不相等,返回 false。

复杂度分析

解法 时间复杂度 空间复杂度 优点 缺点
预处理 + 双指针 O(n) O(n) 思路直观,代码简洁,易理解,不易出错 需要额外存储预处理后的字符串,占用空间
原地双指针 O(n) O(1) 空间最优,适合大规模字符串,效率更高 需要处理指针跳过无效字符的逻辑,细节稍多

总结

验证回文串的核心:先过滤无效字符、统一大小写,再通过双指针验证对称性。

  • 面试中,若不要求空间优化,优先写「预处理 + 双指针」解法,代码简洁、不易出错,能快速完成答题。

  • 若面试官要求空间复杂度 O(1),则使用「原地双指针」解法,重点注意跳过无效字符的逻辑,避免指针越界。

  • 本题的关键细节:忽略大小写、只考虑字母数字,这两个点容易遗漏,解题时需重点关注。

今天的每日算法练习就到这里,我们明天再见!👋

相关推荐
octopus_c2 小时前
数据结构:堆(Heap)详解
c语言·数据结构·算法
YH55269848 小时前
GPT‑5.6 Sol 原本支持 1M 上下文,Codex 现已放开此前限制,如何看待这次调整?
java·jvm·人工智能·gpt·算法·chatgpt
遥感知识服务9 小时前
从局部阈值、双极化到暗地表剔除:NASA OPERA DSWx-S1全球动态水体算法拆解
大数据·人工智能·深度学习·神经网络·算法·机器学习
晚风醉蝶9 小时前
1-13-TimSort
算法
ZJU_统一阿萨姆10 小时前
【算子开发】算子融合与Softmax_LayerNorm实现
人工智能·算法·语言模型·硬件架构
叩码以求索11 小时前
浅谈:前序遍历反转法求解N叉树的后序遍历
算法
官乐13 小时前
AI面试指南(多agent开发流程)
人工智能·面试·职场和发展
北风toto13 小时前
中缀、前缀、后缀表达式
算法·软件设计师
程序员三藏13 小时前
自动化测试用例编写详解
自动化测试·软件测试·python·功能测试·测试工具·职场和发展·测试用例
听取WA声一片(无恶意)13 小时前
CSP-J/CSP-S 深度优先搜索(DFS)完全讲义
c++·算法·深度优先