在问 · 算法题解

125. 验证回文串

简单双指针原地双指针力扣原题 ↗

题目描述

输入一个字符串 s。先删掉其中所有不是字母或数字的字符,再把大写字母全部换成小写。

如果处理后的字符串从左往右读和从右往左读完全相同,它就是回文串。

s 是回文串时返回 true,否则返回 false。处理后为空串也算回文。

示例 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^5
  • s 只含可打印的 ASCII 字符。

解题思路:原地双指针

回文的定义是第 k 个有效字符等于倒数第 k 个有效字符。用左右两个指针从两端向中间走:先各自跳过非字母数字字符,再比较两个字符的小写形式。只要有一对不同就能立刻返回 false;两指针相遇说明所有对称位置都相同。这样不需要额外构造清洗后的字符串。

为什么正确

每轮开始时,s[:i] 与 s[j+1:] 中的有效字符已经两两对称匹配。

复杂度分析

时间 O(n),每个字符最多被一个指针经过一次;额外空间 O(1)。

易错点

跳过非字母数字字符的内层循环也要带上 i < j 条件,否则全是标点时指针会越界;另外数字也是有效字符,不能只判断字母。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def isPalindrome(self, s: str) -> bool:
        i, j = 0, len(s) - 1
        while i < j:
            while i < j and not s[i].isalnum():
                i += 1
            while i < j and not s[j].isalnum():
                j -= 1
            if s[i].lower() != s[j].lower():
                return False
            i, j = i + 1, j - 1
        return True

载入编辑器,自己跑一遍 →

其他解法

过滤后反转比较写法简单,占 O(n) 空间;原地双指针边跳过边比较,只用 O(1) 空间,还能提前返回。

解法 2:过滤后反转比较 时间 O(n),空间 O(n)

先遍历一遍,只保留字母和数字并转成小写,得到新字符串 t。再把 t 反转,判断反转后是否与 t 相等。

把“清洗”和“判断回文”拆成两步,代码最短,不容易写错。需要 O(n) 额外空间,且即使首尾就不同也要先处理完整个字符串。

class Solution:
    def isPalindrome(self, s: str) -> bool:
        t = [c.lower() for c in s if c.isalnum()]
        return t == t[::-1]

双指针 专题的其他题目

查看 双指针 全部题目 →