题目
给定一个字符串 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 字符组成
解析
遍历 + 判断
遍历字符串s的每一个字符,如果发现是数字或者字母, 统一变成小写添加到数组s2中保存, 把数组s2的反转后得到s3, 最后判断 s2.join('') === s3.jon('') 二者是否相同即可。
注意由于数组的reverse方法会改变原数组,所以使用slice方法进行一次浅拷贝
双指针
思路比较巧妙,字符串是回文,说明左边的部分的子串和右边的子串相等
因此:声明左右两个指针分别指向数组的头尾,然后左指针向前走,右指针向后走,指针在遇到非数字或者字母的字符跳过,直到左右指针相遇,如果在左右指针走的过程它们指向的字符不相等,说明不是回文字符串,反之,当指针相遇时,说明左右的字符串都相同,说明是回文字符串
为什么是终止条件是 left < right?, 考虑当字符串s的长度为1, 如a, 它也满足回文字符串的定义
参考代码
遍历 + 判断
/**
* @param {string} s
* @return {boolean}
*/
var isPalindrome = function(s) {
const numberOrDigitRegex = /[0-9a-zA-Z]/;
const s2 = [];
for (let char of s) {
if (numberOrDigitRegex.test(char)) {
s2.push(char.toLocaleLowerCase());
}
}
const s3 = s2.slice().reverse();
return s2.join('') === s3.join('');
};
双指针
/**
* @param {string} s
* @return {boolean}
*/
var isPalindrome = function(s) {
let left = 0, right = s.length - 1;
while(left < right) {
while (!/[a-zA-Z0-9]/.test(s[left]) && left < right) {
left++;
}
while (!/[a-zA-Z0-9]/.test(s[right]) && left < right) {
right--;
}
if (s[left].toLowerCase() != s[right].toLowerCase()) {
return false;
}
left++;
right--;
}
return true;
};