1. 问题描述
最长公共子序列:常用于解决字符串的相似度,是指在母串中都出现过并且出现顺序与母串保持一致的子串,不要求连续性。
最长公共子串:是指在母串中连续出现的子串。
例如:
cnblogs
belong
最长公共子序列为blog,最长公共子串为lo
2. 动态规划——最长公共子序列
假设
Z=<z1,z2,⋯,zk>
是母串
X
与
- 如果 xm=yn ,则 zk=xm=yn ,并且 Zk−1 是 Xm−1 与 Yn−1 的LCS;
- 如果 xm≠yn ,则 Zk 是 Xm−1 与 Yn 或者 Xm 与 Yn−1 的LCS;
用二维数组
dp[i][j]
记录串
x1,x2,⋯,xi
与
y1,y2,⋯,yj
的LCS长度,则可得到状态转移方程:
dp[i][j]=⎧⎩⎨⎪⎪0,dp[i−1][j−1]+1max(dp[i][j−1],dp[i−1][j]) if i=0 || j=0 if i,j>0 && xi=yj if i,j>0 and xi≠̸yj
代码实现
//最长公共子序列
int LongestCommonSubsequence(string a, string b){
int alen = a.length();
int blen = b.length();
if(alen <= 0 || blen<= 0)
return 0;
int dp[alen+1][blen+1];
for(int i = 0; i <= alen; ++i)
for(int j = 0; j <= blen; ++j){
if(i == 0 || j == 0)
dp[i][j] = 0;
else if(a[i-1] == b[j-1])
dp[i][j] = dp[i-1][j-1] +1;
else
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
return dp[alen][blen];
}
3. 动态规划——最长公共子串
最长公共子串是最长公共子序列的一种特殊情况,考虑到最长公共子串的连续性,定义状态转移方程如下:
dp[i][j]=⎧⎩⎨⎪⎪0,dp[i−1][j−1]+10 if i=0 || j=0 if i,j>0 && xi=yj if i,j>0 and xi≠̸yj
最长公共子串的长度为
max(c[i,j]),i∈(1,⋯,m),j∈(1,⋯,n)
。
代码实现
//最长公共子串
int LongestCommonSubstring(string a, string b){
int alen = a.length();
int blen = b.length();
if(alen <= 0 || blen<= 0)
return 0;
int dp[alen+1][blen+1];
int result = 0;
for(int i = 0; i <= alen; ++i)
for(int j = 0; j <= blen; ++j){
if(i == 0 || j == 0)
dp[i][j] = 0;
else if(a[i-1] == b[j-1]){
dp[i][j] = dp[i-1][j-1] +1;
result = max(result, dp[i][j]);
}
else
dp[i][j] = 0;
}
return result;
}
4. 添加/删除最少字符使得字符串整体为回文字符串
解题思路:
如果能在母串S中找到最长的子序列L,并且这个子序列是回文,那么插入ans = strlen(s) - strlen(L)个字符就能使得原串成为回文字符串。
问题转为求一个字符串的最长回文子序列,这个问题可以使用最长公共子序列的解法,解法如下:
1.求S的逆序串 S’,;
2.求S和S’的最长公共子序列L,L即为S的最长回文子序列;
3.ans = strlen(s) - strlen(L)。
例如: S = abca 那么 S’ = acba ,那么L = aba 那么答案就是1。即 a‘c’bca。其中’c’为插入的字符。
代码实现
//添加最少字符使得字符串整体为回文字符串
int getPalindrome(string str){
int len = str.length();
if(len <= 0)
return 0;
//得到母串的逆序字符串
string invertedstr;
for(int i = len - 1; i >= 0; --i){
string temp {str[i]};
invertedstr.append(temp);
}
//得到母串与其逆序字符串的最长公共子序列长度
int lcslen = LongestCommonSubsequence(str, invertedstr);
return len - lcslen;
}