描述
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
示例1
分析:
1)方法一:动态规划(时间复杂度高)
一看到两个字符串的“最值”问题,一般想到二维dp。很自然地想到把str1前i个字符和str2前j个字符最长公共子串的长度作为dp[i][j]
,但由于子串定义必须是原字符串连续的序列,这样定义无法找到递推关系,因此需要加限定条件——以str1[i-1]
和str2[j-1]
结尾的最长公共子串长度。(当前的最长公共子串的结尾是str1[i-1]和str2[j-1]
),用maxlen记录当前最长公共子串的长度。
/**
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
function LCS( str1 , str2 ) {
//1. 其中有一个是空串
if(str1 == null || str2 == null){
return "";
}
//2.动态规划
let l1 = str1.length;
let l2 = str2.length;
let dp = new Array(l1);
let maxlen = 0;
let index = 0;
for(let i=0; i<l1; i++){
dp[i] = new Array(l2);
}
//初始化。如果不赋初值为0,相加时,会直接变为NaN
for(let i=0; i<l1; i++){
for(let j=0; j<l2; j++){
dp[i][j] = 0;
}
}
for(let i=0;i<l1;i++){
for(let j=0;j<l2;j++){
if(str1[i] == str2[j]){
if(i==0 || j==0){
dp[i][j] = 1;
}else{
dp[i][j] = dp[i-1][j-1]+1;
}
if(maxlen < dp[i][j]){
maxlen = dp[i][j];
index = i;
}
}//if
}//for
}//for
if(maxlen == 0) return "";
return str1.slice(index-maxlen+1, index+1);
}
module.exports = {
LCS : LCS
};
2)方法二:使用滑动窗口的思想
/**
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
function LCS( str1 , str2 ) {
//寻找较短字符串的子串,看其是否是较长字符串的子串
//1. str1中存放较短的字符串
if(str1.length > str2.length){
[str1, str2] = [str2, str1];
}
let len = str1.length;
let maxlen = 0; //依次对最大长度递增 。最大长度为maxlen+1
let res = ''; //最长的公共子串
//2. 寻找较短字符串的子串。只需要寻找比上一个公共子串 长的 子串
for(let i=0; i<len; i++){
// 当前子串. 长度为maxlen+1的子串
let tempstr = str1.slice(i-maxlen, i+1);
if(str2.indexOf(tempstr) != -1){ //str2中存在该子串
res = tempstr;
maxlen++; //继续寻找最大长度为maxlen+1的子串
}
}
return res;
}
module.exports = {
LCS : LCS
};