🚀 问题描述
如果一个短语在:
- 将所有大写字母转换为小写。
- 删除所有非字母数字字符后。
该短语正读和反读相同,则它是回文的。
如果输入字符串 s 是回文的,则返回 true;否则,返回 false。
💡 示例
示例 1
输入:s = "A man, a plan, a canal: Panama"
输出:true
解释:清理后,"amanaplanacanalpanama" 正读和反读相同。
示例 2
输入:s = "race a car"
输出:false
解释:清理后,"raceacar" 不是回文。
示例 3
输入:s = " "
输出:true
解释:清理后,字符串为空,被认为是回文。
🏆 JavaScript 解决方案
我们可以使用双指针方法来检查清理后的字符串是否是回文。
实现代码
var isPalindrome = function(s) {
let left = 0;
let right = s.length - 1;
while (left < right) {
while (left < right && !isAlphanumeric(s[left])) left++;
while (left < right && !isAlphanumeric(s[right])) right--;
console.log('left', left)
console.log('right', right)
if (s[left].toLowerCase() !== s[right].toLowerCase()) {
return false;
}
left++;
right--;
}
return true;
};
function isAlphanumeric(char) {
return /^[a-zA-Z0-9]$/.test(char);
}
console.log(isPalindrome("A man, a plan, a canal: Panama"))
🔍 工作原理
- 双指针:
-
- 从字符串的开头(
left)和结尾(right)开始设置指针。 - 将指针向中间移动。
- 从字符串的开头(
- 跳过非字母数字字符:
-
- 使用函数
isAlphanumeric()来确定有效字符。 - 通过移动指针跳过无效字符。
- 使用函数
- 比较字符:
-
- 使用
toLowerCase()将两个字符都转换为小写后再进行比较。 - 如果字符不匹配,返回
false。
- 使用
- 检查所有字符:
-
- 如果循环完成而没有不匹配的情况,返回
true。
- 如果循环完成而没有不匹配的情况,返回
🔑 复杂度分析
- 时间复杂度:
O(n),其中 n 是字符串的长度。
-
- 每个字符都会被双指针处理一次。
- 空间复杂度:
O(1),因为没有使用额外的数据结构。
📋 运行示例
输入:"A man, a plan, a canal: Panama"
输出:true
替代解决方案:清理并反转
另一种方法是清理字符串并检查它是否与其反转后的字符串匹配。
var isPalindrome = function(s) {
const cleaned = s.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
return cleaned === cleaned.split('').reverse().join('');
};
复杂度:
- 时间复杂度:
O(n),用于清理、反转和比较字符串。 - 空间复杂度:
O(n),用于清理后的字符串和反转后的字符串。
✨ 面试技巧
- 处理边界情况:
-
- 空字符串(
"")→true。 - 只包含非字母数字的字符串(例如,
"!!")→true。
- 空字符串(
- 效率:
-
- 双指针方法在空间上更高效。
- 清理和反转的方法更简单,但使用了更多内存。
- 解释辅助函数:
-
- 讨论为什么使用基于正则表达式的
isAlphanumeric()是清晰且有效的。
- 讨论为什么使用基于正则表达式的