回文串的经典题型:最长回文子串
回文串的长度可能是奇数,也可能是偶数,所以要分开考虑
ABBA: 回文中心是BB之间的间隙;ABA:回文中心是B
- 为了简单化问题我们可以用一个字符串中没出现过的字符来进行填充,让它都变成长度为奇数的串,如#A#B#B#A#(后面都以此为例)
- 然后再利用中心扩散的思想,求解
以str[0]为回文中心是,左边扩散是边界,右边是A,故它能扩散0步
我们可以填这样一个表
ch | # | A | # | B | # | B | # | A | # |
---|---|---|---|---|---|---|---|---|---|
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
p | 0 | 1 | 0 | 1 | 4 | 1 | 0 | 1 | 0 |
观察发现,最长回文子串就是p数组的最大值
function solution(str) {
str = '#' + str.split('').join('#') + '#';
let len = str.length;
const p = new Array(len);
const fn = (index) => {
let i = index - 1, j = index + 1;
let step = 0;
while(i >= 0 && j < len && str[i] === str[j]){
i--;
j++;
step++;
}
return step;
};
for(let i = 0; i < len; i++){
p[i] = fn(i);
}
return Math.max(...p);
}
扩展一下,如果是带有*号的字符串,*表示任意一个字母,只需要修改一下中心扩散的判定条件即可
console.log(solution('DAB*B*ACD'));
function solution(str) {
str = '#' + str.split('').join('#') + '#';
let len = str.length;
const p = new Array(len);
const fn = (index) => {
let i = index - 1, j = index + 1;
let step = 0;
while(i >= 0 && j < len){
if(str[i] === str[j] || (str[i] === '*' || str[j] === '*')){
i--;
j++;
step++;
}
else break;
}
return step;
};
for(let i = 0; i < len; i++){
p[i] = fn(i);
}
return Math.max(...p);
}