关注
文末的名片达文汐
,回复关键词“力扣源码”,即可获取完整源码!!详见:源码和核心代码的区别
题目详情
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串。字母和数字都属于字母数字字符。
给你一个字符串 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 是一个空字符串 “” 。
由于空字符串正着反着读都一样,所以是回文串。
提示:
1 <= s.length <= 2 * 10^5
s
仅由可打印的 ASCII 字符组成
解题思路
- 双指针法:使用左右指针从字符串两端向中间扫描,跳过非字母数字字符。
- 原地处理:不构建新字符串,直接在原字符串上操作,节省内存。
- 字符处理:
- 使用
Character.isLetterOrDigit()
判断字母数字字符。 - 使用
Character.toLowerCase()
统一转小写。
- 使用
- 比较逻辑:
- 左指针右移直到找到字母数字字符。
- 右指针左移直到找到字母数字字符。
- 比较左右指针字符(忽略大小写),若不等则返回
false
。
- 边界处理:空字符串或全非字母数字字符时,左右指针会相遇,返回
true
。
时间复杂度:O(n),每个字符最多访问两次。
空间复杂度:O(1),仅使用常量空间。
代码实现(Java版)
class Solution {
public boolean isPalindrome(String s) {
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--;
}
// 比较左右指针字符(忽略大小写)
if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
return false;
}
// 移动指针继续比较
left++;
right--;
}
return true;
}
}
代码说明
- 双指针初始化:
left
从索引 0 开始(字符串开头)。right
从索引s.length()-1
开始(字符串末尾)。
- 循环条件:
left < right
,确保指针有效移动。 - 跳过非字母数字字符:
- 内层循环移动
left
直到找到字母数字字符。 - 内层循环移动
right
直到找到字母数字字符。
- 内层循环移动
- 字符比较:
- 将左右指针的字符转为小写后比较。
- 若不相等,直接返回
false
。
- 指针更新:比较后同时移动
left
和right
继续扫描。 - 循环结束:所有有效字符均匹配,返回
true
。