1.最大公共子序列
例如:BDCABA和ABCBDAB的最大公共子序列是BCBA。
找两个递增下标序列<i1,i2,...,ik>和<j1,j2,...jk>,使得str1[i1]=str2[j1],str1[i2]=str2[j2],...,str1[ik]=str2[jk]。
用动态规划来求解:
DP[i][j]来表示str1的前i个元素与str2的前j个元素能够组成的最大子序列的长度。
str1=BDCABA
str2=ABCBDAB
则DP[1][1]=0
DP[1][2]=1
DP[3][3]=2
所以可得状态方程为:
0, i=0或者j=0
DP[i][j]= DP[i-1][j-1]+1, str1[i]==str2[j]
Max(DP[i+1][j],DP[i][j+1]) ,其他
实现如下:
#include<iostream>
#include <vector>
#include <assert.h>
#include <string>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
vector<char> LongestSubSeq(char *str1, char *str2)
{
int size1 = strlen(str1);
int size2 = strlen(str2);
vector<char> result;
int max = 0;//当前最大长度,更新该数据的目的是为了将合适的字符写入到result中
vector<vector<int>> DP(size1+1, vector<int>(size2+1, 0));
for (int i = 0; i < size1; i++)
for (int j = 0; j < size2; j++)
{
if (str1[i] == str2[j]) DP[i + 1][j + 1] = DP[i][j] + 1;
else DP[i + 1][j + 1] = Max(DP[i+1][j],DP[i][j+1]);
if (DP[i + 1][j + 1] > max)
{
max = DP[i + 1][j + 1];
result.push_back(str1[i]);
}
}
return result;
}
int main(void)
{
char a[] = "abcdefghijklmn";
char b[] = "acefnq";
vector<char> re = LongestSubSeq(a, b);
for (int i = 0; i < re.size(); i++)
cout << re[i];
cout << endl;
return(0);
}
2.最大公共子串
例如:BDCABA和ABCBDAB的最大公共子串是BD和AB。
找两个递增下标序列<i1,i2,...,ik>和<j1,j2,...jk>,使得str1[i1]=str2[j1],str1[i2]=str2[j2],...,str1[ik]=str2[jk]。且递增下标每次增加1。
也可以用动态规划做,如果 str1[i]==str2[j],则DP[i][j]=DP[i-1][j-1]+1。
如果str1[i]!=str2[j],则DP[i][j]=0。这是区别所在。
#include<iostream>
#include <vector>
#include <assert.h>
#include <string>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
vector<char> LongestSubSeq(char *str1, char *str2)
{
int size1 = strlen(str1);
int size2 = strlen(str2);
vector<char> result;
int max = 0;//当前最大长度,更新该数据的目的是为了将合适的字符写入到result中
vector<vector<int>> DP(size1+1, vector<int>(size2+1, 0));
for (int i = 0; i < size1; i++)
for (int j = 0; j < size2; j++)
{
if (str1[i] == str2[j]) DP[i + 1][j + 1] = DP[i][j] + 1;
else DP[i + 1][j + 1] = 0;
if (DP[i + 1][j + 1] == max)
{
result.pop_back();
result.push_back(str1[i]);
}
if (DP[i + 1][j + 1] > max)
{
max = DP[i + 1][j + 1];
result.push_back(str1[i]);
}
}
cout << max << endl;
return result;
}
int main(void)
{
char a[] = "abcdefgabcdefgh";
char b[] = "acdefnqabcdefgh";
vector<char> re = LongestSubSeq(a, b);
for (int i = 0; i < re.size(); i++)
cout << re[i];
cout << endl;
return(0);
}