验证回文串

标签: 双指针 字符串

难度: Easy

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

本题中,将空字符串定义为有效的 回文串 

示例 1:

输入: s = "A man, a plan, a canal: Panama"
输出: true
解释:"amanaplanacanalpanama" 是回文串

示例 2:

输入: s = "race a car"
输出: false
解释:"raceacar" 不是回文串

提示:

  • 1 <= s.length <= 2 * 105
  • 字符串 s 由 ASCII 字符组成

注意:本题与主站 125 题相同: https://leetcode-cn.com/problems/valid-palindrome/

Submission

运行时间: 28 ms

内存: 16.2 MB

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

Explain

题解采用双指针策略来验证回文串。首先,定义两个指针a和b,分别指向字符串的开始和结束位置。然后,使用两个while循环分别从两端跳过非字母和数字的字符。接着,若两个指针所指的字符在忽略大小写的情况下不相等,则直接返回False。如果指针所指的字符相等,就将两个指针分别向中间移动,继续比较下一对字符。当两个指针相遇或者交叉时,说明整个字符串是回文串,返回True。

时间复杂度: O(n)

空间复杂度: O(1)

class Solution:
    def isPalindrome(self, s: str) -> bool:
        a, b = 0, len(s)-1
        while a < b:
            while a < b and not s[a].isalnum():
                a += 1  # 跳过左侧非字母数字字符
            while a < b and not s[b].isalnum():
                b -= 1  # 跳过右侧非字母数字字符
            if a < b:
                if s[a].lower() != s[b].lower():
                    return False  # 对比两端字符,若不相同则不是回文串
                a += 1  # 移动左指针向中心
                b -= 1  # 移动右指针向中心
        return True  # 所有字符对比完毕,均相同,是回文串

Explore

在双指针策略中,确保忽略大小写后字符的比较准确的方法是使用Python的 `lower()` 或 `upper()` 方法将字符转换为相同的大小写形式后进行比较。特殊情况主要涉及到国际化场景,例如某些语言中的特殊字符和重音符号可能不会通过简单的 `lower()` 或 `upper()` 方法正确处理。在这种情况下,可能需要使用更复杂的规范化方法来确保字符的正确比较,如Unicode规范化。然而,对于LeetCode题目中通常处理的字符范围(ASCII字符),使用 `lower()` 或 `upper()` 方法是足够的。

当字符串长度非常大时,双指针方法特别适用于这种情况,原因在于其时间复杂度为O(n),空间复杂度为O(1)。这意味着算法的执行时间与字符串的长度成线性关系,且不需要额外的存储空间。相比于需要额外存储空间或时间复杂度更高的方法,如反转字符串后进行比较(空间复杂度O(n)),双指针方法更高效,尤其是在处理大量数据时。

是的,确实存在某些情况下字符会被访问少于两次的情况。例如,如果字符串中间的字符是非字母数字字符,当外侧的指针在向内移动时会跳过这些字符,这些字符可能永远不会被检查。例如在字符串'ab2!2ba'中,中间的'!'在比较过程中被跳过,只有字母和数字字符被访问过。另一个情况是当字符串本身就是回文且长度为奇数时,中间的字符只会被访问一次。