445 字
2 分钟
125. 验证回文串
125. 验证回文串
题目描述
题目链接: LeetCode 125
如果在将所有大写字符转换为小写并移除所有非字母数字字符之后,正着读和反着读都一样的字符串,则它就是一个回文串。给定一个字符串 s,如果它是回文串,返回 true,否则返回 false。
示例:
输入:s = "A man, a plan, a canal: Panama"输出:true解释:"amanaplanacanalpanama" 是回文串。解题思路
核心思想
回文串对称比较,天然适合相向双指针:左指针指向开头、右指针指向结尾,跳过所有非字母数字字符后,比较两字符是否相等(忽略大小写)。若出现不等则不是回文串。
算法步骤
left = 0, right = len(s) - 1- 当
left < right:- 跳过非字母数字:左指针右移直到
s[left].isalnum(),右指针左移直到s[right].isalnum() - 比较
s[left].lower() == s[right].lower(),不等则返回False left += 1, right -= 1
- 跳过非字母数字:左指针右移直到
- 返回
True
逐步举例
s = "A man, a plan, a canal: Panama"
| 字符(原文) | 处理 | 比较 |
|---|---|---|
A vs a | 跳过空格和标点后,忽略大小写 | a == a ✅ |
m vs m | — | ✅ |
a vs a | — | ✅ |
| … | 逐渐逼近中央 | … |
P vs n 前 | — | 最终全部对称 ✅ |
返回 true。
复杂度分析
- 时间复杂度:O(n),每个字符最多访问一次
- 空间复杂度:O(1),只用了两个指针
代码实现
class Solution: def isPalindrome(self, s: str) -> bool: left, right = 0, len(s) - 1 while left < right: while left < right and not s[left].isalnum(): left += 1 while left < right and not s[right].isalnum(): right -= 1 if s[left].lower() != s[right].lower(): return False left += 1 right -= 1 return Trueimport sysfrom pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
import unittest
from solution import Solution
class Test125(unittest.TestCase): def test_example1(self): self.assertTrue(Solution().isPalindrome("A man, a plan, a canal: Panama"))
def test_example2(self): self.assertFalse(Solution().isPalindrome("race a car"))
def test_empty_space(self): self.assertTrue(Solution().isPalindrome(" "))
def test_underscore(self): self.assertTrue(Solution().isPalindrome("ab_a"))
if __name__ == '__main__': unittest.main()