题目
给定一个字符串,求字符串的最长回文子序列
-
遍历模型为遍历每一个子串,dp[i][j],i、j表示从 i 到 j范围的子串,首先 i 不可能大于 j,当 i==j 时,区间长度为1,所以最长回文子序列全是1,当对角线的右边的斜线时即[i,i-1]范围时,区间长度为2,当 i 和 i-1位置相等时,最长回文子序列为2,否则为1
-
对其余情况进行可能性分析,分为四种情况,在 [i,j]范围上,枚举出最长子序列可能出现的所有可能,虽然各个可能性区间会有重复,但保证了一定能统计出所有情况
- 如果子串的最长回子序列和 i、j位置无关,则为 dp[i-1][j-1]
- 如果子串的最长回文子序列和 i 有关,和 j 无关,则为 dp[i][j-1]
- 如果子串的最长回文子序列和 i 无关,和 j 有关,则为 dp[i-1][j]
- 如果子串的最长回文子序列以 i、j为首尾,则子序列为 dp[i-1][j-1]+2
-
其余位置在填写的时候从左往右,从上往下一列一列填写
function process(str) {
let row = str.length,
col = str.length,
max = 0;
// 对角线长度为1
for (let i = 0; i < row; i++) {
dp[i][i] = 1;
}
// 对角线右边的斜线
for (let i = 1; i < row; i++) {
if (str[i] === str[i - 1]) {
dp[i][i - 1] = 2;
} else {
dp[i][i - 1] = 1;
}
}
// 其余情况进行可能性分析
for (let i = 2; i < row; i++) {
for (let j = 0; j <= i - 2; j++) {
res = Math.max(res, dp[i - 1][j - 1]);
res = Math.max(res, dp[i][j - 1]);
res = Math.max(res, dp[i - 1][j]);
if (str[i] === str[j]) {
res = Math.max(res, dp[i - 1][j - 1] + 2);
}
}
}
return dp[0][row]; // 返回 [0,row] 范围的最长回文子序列就是答案
}