0125.验证回文串

难度:🟢 简单

标签双指针字符串

链接125. 验证回文串

题目描述

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样,则可以认为该短语是一个 回文串

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false

示例 1:

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

示例 2:

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

示例 3:

输入:s = " "
输出:true
解释:在移除非字母数字字符之后,s 是一个空字符串 "" 。由于空字符串正着反着读都一样,所以是回文串。

解题思路

核心思想

本题的核心是在判断回文串之前,先对原始字符串进行“清洗”。我们需要忽略所有非字母和非数字的字符(如空格、标点符号),并且在比较时忽略字母的大小写。

思路选择

双指针法 是解决此问题的最优思路。

  • 我们设置两个指针,leftright,分别从字符串的头部和尾部开始。

  • 两个指针同时向中间移动。在移动过程中,如果遇到非字母数字字符,就跳过它。

  • 当两个指针都指向有效的字母数字字符时,就将它们转换为小写并进行比较。如果不相等,则该字符串不是回文串。如果相等,则继续向中间移动。

  • left 指针越过 right 指针时,说明所有有效的字符都已比较完毕且匹配,该字符串是回文串。

关键步骤

  1. 初始化:创建两个指针,left = 0right = s.length - 1

  2. 循环比较:当 left < right 时,持续循环。 a. 移动左指针:如果 s[left] 不是有效字符,则 left++,继续下一轮循环。 b. 移动右指针:如果 s[right] 不是有效字符,则 right--,继续下一轮循环。 c. 比较字符:当左右指针都指向有效字符时,将它们都转换为小写进行比较。如果 s[left].toLowerCase() !== s[right].toLowerCase(),则立即返回 false。 d. 收缩范围:如果字符相等,则将两个指针向中间移动,left++right--

  3. 返回结果:如果循环正常结束,说明字符串是回文的,返回 true

代码实现 (推荐)

/**
 * @param {string} s
 * @return {boolean}
 */
var isPalindrome = function (s) {
    let left = 0, right = s.length - 1;
    const reg = /^[a-zA-Z0-9]$/; // 正则表达式用于验证字母数字字符

    while (left < right) {
        // 从左边找到第一个有效字符
        if (!reg.test(s[left])) {
            left++;
            continue;
        }
        // 从右边找到第一个有效字符
        if (!reg.test(s[right])) {
            right--;
            continue;
        }

        // 比较两个有效字符(忽略大小写)
        if (s[left].toLowerCase() !== s[right].toLowerCase()) {
            return false;
        }

        // 移动指针
        left++;
        right--;
    }

    return true;
};

原始代码分析 (用户提供)

您提供的解法逻辑完全正确,通过一个辅助函数来判断字符有效性,思路清晰。

// 辅助函数,判断字符是否为字母或数字
var isValidChar = function (str) {
    return (str <= 'Z' && str >= 'A') || (str <= 'z' && str >= 'a') || (str <= '9' && str >= '0');
}

/**
 * @param {string} s
 * @return {boolean}
 */
var isPalindrome = function (s) {
    let left = 0, right = s.length - 1;

    // 主循环,当左指针在右指针左边或重合时
    while (left <= right) {
        // 内循环,跳过左边的无效字符
        while (!isValidChar(s[left]) && left <= right) {
            left++;
        }
        // 内循环,跳过右边的无效字符
        while (!isValidChar(s[right]) && left <= right) {
            right--;
        }

        // 再次检查指针是否越界
        if (left <= right) {
            // 比较并移动指针
            if (s[left].toLowerCase() === s[right].toLowerCase()) {
                left++;
                right--;
            } else return false;
        }
    }
    return true;
};
  • 优点:逻辑正确,并且将字符验证的逻辑封装在辅助函数中,代码结构清晰。

  • 潜在优化点:代码中使用了嵌套的 while 循环,虽然功能正确,但可读性上可以稍作调整。推荐解法中使用 continue 将逻辑扁平化在单个 while 循环内,有时会更易于理解。

复杂度分析

  • 时间复杂度O(n) 其中 n 是字符串 s 的长度。双指针最多遍历整个字符串一次。

  • 空间复杂度O(1) 我们只使用了常数个额外变量。

相关题目

总结

本题是双指针技巧的经典应用。通过“从两端向中间”的策略,并结合适当的过滤条件,可以非常高效地解决回文判断问题。这种处理字符串(或数组)两端关系的模式非常常用。

Copyright © Jun 2025 all right reserved,powered by Gitbook该文件修订时间: 2025-07-03 17:35:08

results matching ""

    No results matching ""

    results matching ""

      No results matching ""