最长回文子串(提供点想法,因为需要了解的点可能比较多)
这道题其实与最长重复子数组那道题有点类似,之所以这么说是因为可以将原字符反转过来,然后找到两个字符串的最长公共子串其实就解决了一大半了(创建一个dp,然后dp[i][j]用于记录当前子串最长的长度,如果两个字符串当前的值不相等记录dp[i][j]=0),唯一棘手的是最长公共子串不一定是最长的回文子串,判断方法思路是在这里找到的,确实比较反人类。。。
var longestPalindrome = function (s) {
const reverse = s.split("").reverse().join("");
const n = s.length;
const dp = new Array(n + 1).fill([]).map(() => new Array(n + 1).fill(0));
let maxLen = 0;
let start = 0;
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {
if (s[i - 1] === reverse[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = 0;
};
if (dp[i][j] > maxLen) {
const before = n - (j - 1) - 1;
if (before + dp[i][j] - 1 === (i - 1)) {
maxLen = dp[i][j];
start = i - maxLen;
};
};
};
};
return s.substr(start, maxLen);
};
复杂度还是很高,然后降维:
var longestPalindrome = function (s) {
const reverse = s.split("").reverse().join("");
const n = s.length;
const dp = new Array(n + 1).fill(0);
let maxLen = 0;
let start = 0;
for (let i = 1; i <= n; i++) {
for (let j = n; j >= 1; j--) {
if (s[i - 1] === reverse[j - 1]) {
dp[j] = dp[j - 1] + 1;
} else {
dp[j] = 0;
};
if (dp[j] > maxLen) {
const before = n - (j - 1) - 1;
if (before + dp[j] - 1 === (i - 1)) {
maxLen = dp[j];
start = i - maxLen;
};
};
};
};
return s.substr(start, maxLen);
};
j之所以反着遍历是因为,需要用上一次的j,也就是j-1要保证是上次的,如果正着遍历的话则是新的j-1,已经发生了变化.
或是中心扩散发,最好理解:
var longestPalindrome = function (s) {
let res = "";
const spred = (l, r) => {
while (l >= 0 && r < s.length && s[l] === s[r]) {
l--;
r++;
};
return s.substr(l + 1, r - l - 1);
};
for(let i=0;i<s.length;i++){
//字符串长度可能是偶数也可能是奇数
const t1 = spred(i,i);
const t2 = spred(i,i+1);
const t = t1.length>t2.length?t1:t2;
res = t.length>res.length?t:res;
};
return res;
};