一、题目描述
给定一个字符串 s,判断它是否是回文字符串。
核心规则:
只考虑字符串中的字母和数字字符,忽略所有非字母数字字符(如空格、逗号、冒号、符号等)。
忽略字母的大小写(例如 'A' 和 'a' 视为相同字符)。
空字符串或仅包含非字母数字的字符串,视为有效回文字符串。
二、输入输出示例
示例1(有效回文)
输入:"A man, a plan, a canal: Panama"
输出:true
说明:过滤后有效字符串为 "amanaplanacanalpanama",正读和反读一致。
示例2(无效回文)
输入:"race a car"
输出:false
说明:过滤后有效字符串为 "raceacar",正读和反读不一致。
示例3(边界情况)
输入:""(空字符串) → 输出:true
输入:" "(全空格) → 输出:true
输入:"0P" → 输出:false('0' 和 'P' 过滤后不相等)
三、最优解法(双指针法)
核心思路:使用左右双指针从字符串两端向中间遍历,跳过无效字符,统一大小写后比较,效率最高(时间复杂度O(n),空间复杂度O(1))。
完整可运行代码
public class Palindrome { // 验证回文字符串核心方法 public boolean isPalindrome(String s) { // 边界判断:空串或仅空白字符,直接返回true if (s == null || s.trim().isEmpty()) { return true; } 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--; } // 统一转为小写,比较当前左右指针指向的字符 char leftChar = Character.toLowerCase(s.charAt(left)); char rightChar = Character.toLowerCase(s.charAt(right)); // 若不相等,直接返回false(不是回文) if (leftChar != rightChar) { return false; } // 指针向中间移动,继续比较 left++; right--; } // 所有有效字符都匹配,返回true(是回文) return true; } // 测试方法(覆盖多种场景) public static void main(String[] args) { Palindrome test = new Palindrome(); // 示例1:有效回文 System.out.println(test.isPalindrome("A man, a plan, a canal: Panama")); // 输出true // 示例2:无效回文 System.out.println(test.isPalindrome("race a car")); // 输出false // 示例3:边界场景 System.out.println(test.isPalindrome("")); // 输出true System.out.println(test.isPalindrome(" ")); // 输出true System.out.println(test.isPalindrome("0P")); // 输出false } }四、关键注意事项(避坑重点)
非字母数字字符的过滤:必须使用
Character.isLetterOrDigit()方法,避免遗漏特殊符号(如冒号、逗号、下划线等)。大小写忽略:必须统一转为小写(或大写)后比较,否则 'A' 和 'a' 会被判定为不相等,导致错误。
边界条件处理:空字符串、全空白字符串、仅包含非字母数字的字符串,都需直接返回true,避免指针越界。
指针循环条件:必须是
left < right,而非left <= right(中间单个字符不影响回文判断,无需比较)。避免额外空间开销:不建议先过滤字符串再判断(会产生O(n)空间),双指针原地判断是最优方案。
五、复杂度分析
时间复杂度:O(n),n为字符串长度,左右指针各遍历一次字符串,无冗余操作。
空间复杂度:O(1),仅使用2个指针变量,未使用额外集合或字符串,原地完成判断。
六、常见错误解法及修正
错误解法1:未过滤非字母数字字符
问题:直接比较所有字符,包括逗号、空格等,导致示例1判断错误。
修正:添加双指针跳过非字母数字字符的逻辑。
错误解法2:未忽略大小写
问题:直接比较原字符,'A' 和 'a' 判定为不相等,导致判断错误。
修正:使用Character.toLowerCase()统一转为小写后比较。
错误解法3:先过滤字符串再反转比较
问题:新建过滤后的字符串和反转字符串,空间复杂度变为O(n),不是最优解。
修正:使用双指针原地判断,避免额外空间开销。