携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情
最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
来源:力扣(LeetCode) 链接:leetcode.cn/problems/lo…
分析
- 要得到最长公共子序列,可以想到对字符串遍历,对于每个字符有两种情况:保留或舍弃,如果是2个字符串,对与每个字符,有4种情况:(1)text1保留,text2保留(2)text1舍弃,text2保留(3)text1保留,text2舍弃(4)text1舍弃,text2舍弃,因此最长公共子序列的长度可以表示为(1)1+helper(i+1,j+1)(2)helper(i+1,j)(3)helper(i,j+1)(4)helper(i+1,j+1)
递归
- 针对这几个状态,设置好出口,可以是用递归来得到答案
- 当两个字符串中有一个提前遍历完了,可以认为两个字符串没有公共子序列,返回0
代码
var longestCommonSubsequence = function(text1, text2) {
const helper = function(i, j) {
if(i == text1.length || j == text2.length) {
return 0;
}
if(text1[i] == text2[j]) {
return 1+helper(i+1, j+1);
} else {
return Math.max(helper(i+1, j), helper(i, j+1));
}
}
return helper(0, 0)
};
动态规划
- 定义mem[i][j]是截止text1遍历到i,text2遍历到j的最长公共子序列的长度
代码
var longestCommonSubsequence = function(text1, text2) {
let mem = new Array(text1.length+1);
for(let i = 0; i < mem.length; i++) {
mem[i] = new Array(text2.length+1).fill(0);
}
for(let i = 1; i <= text1.length; i++) {
for(let j = 1; j <= text2.length; j++) {
if(text1[i-1] == text2[j-1]) {
mem[i][j] = 1+mem[i-1][j-1];
} else {
mem[i][j] = Math.max(mem[i-1][j], mem[i][j-1]);
}
}
}
return mem[text1.length][text2.length];
};
总结
- 本题是很经典的动态规划的题目,是动态规划的套路题,生成[text1.length+1][text2.length+1]的二维数组,然后根据状态转移公式规划,最后dp[text1.length][text2.length]就是答案
- 今天也是有收获的一天