29-验证回文串
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。
方法一:筛选反转法
该方法的核心思路是先筛选出字符串中的字母和数字字符,并将大写字母转换为小写字母,然后将筛选后的字符串反转,最后比较原筛选字符串和反转后的字符串是否相同。
function isPalindrome(s: string): boolean {
// 筛选出字母和数字字符,并转换为小写
let filtered = '';
for (let char of s) {
if (/[a-zA-Z0-9]/.test(char)) {
filtered += char.toLowerCase();
}
}
// 反转筛选后的字符串
let reversed = filtered.split('').reverse().join('');
return filtered === reversed;
}
复杂度分析
- 时间复杂度:(O(n)),其中 n 是字符串
s
的长度。首先需要遍历一次字符串s
进行筛选,时间复杂度为 (O(n));然后对筛选后的字符串进行反转,其长度最多为 n,时间复杂度也为 (O(n))。因此,总的时间复杂度为 (O(n))。 - 空间复杂度:(O(n)),主要用于存储筛选后的字符串和反转后的字符串,其长度最多为 n。
方法二:双指针法
双指针法使用两个指针分别从字符串的首尾开始向中间移动,在移动过程中跳过非字母数字字符,并比较对应位置的字符是否相同。
function isPalindrome(s: string): boolean {
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--;
}
// 比较字符,忽略大小写
if (left < right && s[left].toLowerCase()!== s[right].toLowerCase()) {
return false;
}
left++;
right--;
}
return true;
}
function isAlphanumeric(char: string): boolean {
return /[a-zA-Z0-9]/.test(char);
}
复杂度分析
- 时间复杂度:(O(n)),其中 n 是字符串
s
的长度。两个指针最多遍历字符串一次,因此时间复杂度为 (O(n))。 - 空间复杂度:(O(1)),只使用了常数级的额外空间,主要用于存储指针。
方法三:递归法
递归法通过不断缩小字符串的范围,递归地判断子字符串是否为回文串。
function isPalindrome(s: string): boolean {
return helper(s, 0, s.length - 1);
}
function helper(s: string, left: number, right: number): boolean {
// 跳过非字母数字字符
while (left < right &&!isAlphanumeric(s[left])) {
left++;
}
while (left < right &&!isAlphanumeric(s[right])) {
right--;
}
if (left >= right) {
return true;
}
// 比较字符,忽略大小写
if (s[left].toLowerCase()!== s[right].toLowerCase()) {
return false;
}
return helper(s, left + 1, right - 1);
}
function isAlphanumeric(char: string): boolean {
return /[a-zA-Z0-9]/.test(char);
}
复杂度分析
- 时间复杂度:(O(n)),其中 n 是字符串
s
的长度。递归过程中,每次递归调用都会将问题规模缩小,最多需要 (n/2) 次递归调用,因此时间复杂度为 (O(n))。 - 空间复杂度:(O(n)),主要是递归调用栈的空间开销,最坏情况下递归深度为 (n/2),因此空间复杂度为 (O(n))。
测试用例
const testString = "A man, a plan, a canal: Panama";
console.log(isPalindrome(testString));