寻找最长公共子序列
使用dp来做,建一个二维dp,我们来构建我们的dp二维数组 两种情况:
- 当前两个字符串最后一个字符相等,则当前dp[i][j] = dp[i-1][j-1] + 1,也就是两个字符串去掉最后一个字符,在来找最长公共子序列,最后求出来+1
- 当前两个字符串最后一个字符不等,dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]),也就是两个字符串各去一次最后一个字符与对方不去最后一个字符找最长公共子序列,最后去两个中大的一个。
如何获取这个子序列呢?
通过倒推的方法:
- 当前的dp最右下角dp[i][j],是两个字符串的最长公共子序列的长度值,如果对应的两个字符串里的字符相等,这个位置对应的字符就是最长公共子序列的一个元素,并且直接往右上角移动进行下一次查找
- 如果对应的两个字符串里的字符不相等,那么说明这个dp[i][j]来源于dp[i - 1][j]和dp[i][j - 1],如果其中一个对应的两个字符相等,这个位置对应的字符就是最长公共子序列的一个元素
- 如果dp[i - 1][j]和dp[i][j - 1]对应的两个字符都不相等,我们可以随便选择一个方向移动,然后在继续比较
// 寻找最长公共子序列;
function findLongest(n, o) {
let nLen = n.length + 1;
let oLen = o.length + 1;
let dp = new Array(nLen).fill(0).map((item) => new Array(oLen).fill(0));
for (let i = 1; i < nLen; i++) {
for (let j = 1; j < oLen; j++) {
if (n[i - 1] === o[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
let i = nLen - 1;
let j = oLen - 1;
let max = dp[i][j];
let res = [];
while (dp[i][j] !== 0) {
if (n[i - 1] !== o[j - 1]) {
if (n[i - 2] === o[j - 1]) {
i--;
} else {
j--;
}
} else {
res.unshift(n[i - 1]);
i--;
j--;
}
}
return res.join("");
}
console.log(findLongest("abcsduc", "sducasdfsd"));
参考
寻找最长公共子串
这个子串和子序列不同的点在于:子串是连续的,子序列不需要连续,保持顺序一致即可
- 递推公式就为:dp[i][j] = dp[i-1][j-1] + 1
function findLongest(s1, s2) {
let dp = new Array(s1.length)
.fill(0)
.map((item) => new Array(s2.length).fill(0));
let resultMax = 0;
let maxColumn = 0;
let maxRow = 0;
let s1Len = s1.length;
let s2Len = s2.length;
for (let i = 0; i < s1Len; i++) {
for (let j = 0; j < s2Len; j++) {
if (s1[i] === s2[j]) {
if (i === 0 || j === 0) {
dp[i][j] = 1;
} else {
dp[i][j] = dp[i - 1][j - 1] + 1;
}
if (resultMax < dp[i][j]) {
resultMax = dp[i][j];
maxColumn = j;
maxRow = i;
}
}
}
}
let res = [];
while (maxRow >= 0 && maxColumn >= 0 && dp[maxRow][maxColumn] > 0) {
res.unshift(s2[maxColumn]);
maxRow--;
maxColumn--;
}
return res.join("");
}
console.log(findLongest("cdsfjabcdefgdasf", "abcdefgsdakjhfasdkl"));