当一个问题能以小推大时,往往可以采用动态规划求解。
子序列与子串的区别:子串必须是连续的,而子序列可以是分散的。
最长公共子串
最长公共子串
题目大意:给定两个字符串str1和str2,输出两个字符串的最长公共子串。
分析:设dp[i][j]为以str1[i]和str2[j]为结尾的两个字符串的最长公共子串。
当str[i]==str[j]时,dp[i][j]=dp[i-1][j-1]+1;
当str[i]!=str[j]时,dp[i][j]=0;
同时设maxlen为最长公共子串长度,last为最长公共子串最后一个字母的索引,不断比较len与dp[i][j]的大小进行更新。
js代码
function LCS( str1 , str2 ) {
const dp = new Array(str1.length+1);
for(let i =0;i<dp.length;i++) {
dp[i] = new Array(str2.length+1).fill(0);
}
let last = 0,len=0;
for(let i=1;i<=str1.length;i++) {
for(let j=1;j<=str2.length;j++) {
if(str1[i-1]==str2[j-1]){
dp[i][j]=dp[i-1][j-1]+1;
if(dp[i][j]>len) {
len = dp[i][j];
last = i;
}
}
}
}
if(len>0) {
return str1.substr(last-len,len);
}
else return "";
}
最长公共子序列
最长公共子序列
题目大意:给定两个字符串str1和str2,输出两个字符串的最长公共子序列。
分析: 设dp[i][j]为以str1[i]和str2[j]为结尾的两个字符串的最长公共子序列。
当str1[i]==str2[j]时,dp[i][j]==dp[i-1][j-1]+1;
当str1[i]!=str2[j]时,dp[i][j]=max(dp[i][j-1],dp[i-1][j])
在输出字符串时,设i为str1.length,j为str2.length,res表示最长公共子序列,t表示res中剩下字母数。
当str1[i]=str2[j]时,将str1[i]加入res中,并将t–,
当str1[i]!=str2[j]时,若dp[i-1][j]==t,则将i-1;反之将j-1;
js代码:
function LCS( s1 , s2 ) {
let res = "";
let dp =new Array(s1.length+1);
for(let i=0;i<dp.length;i++) {
dp[i] = new Array(s2.length+1).fill(0);
}
for(let i=1;i<=s1.length;i++) {
for(let j=1;j<=s2.length;j++) {
if(s1[i-1]==s2[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 t=dp[s1.length][s2.length],i=s1.length-1,j=s2.length-1;
while(t>0) {
if(s1[i]==s2[j]) {
res = s1[i].concat(res);
t--,i--,j--;
}
else {
if(dp[i][j+1]==t) i--;
else j--;
}
}
if(res.length) return res;
else return "-1";
}