题意:
给出三个字符串,求出三个公共最长子串长度。
思路:
首先可以确定不同于两个串的公共最长,重复两次。因为C对于A -B 的最长公共子串会造成影响
A: abffgg
B:affgg
C:aa
解法:
首先维护b和c的状态,在这基础上对于每一个a串与二者的状态再进行讨论
dp进阶之路的大神说:
直接把dp[i][j][k]搞成一个字符串……然后状态直接对应方案……
太菜了。。我不懂。也没查到。哪位大神给个代码
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
int dp[300][300][300];
char a[1000];
char b[1000];
char c[1000];
int main()
{
memset(dp,0,sizeof(0));
gets(a);
gets(b);
gets(c);
int lena=strlen(a);
int lenb=strlen(b);
int lenc=strlen(c);
for(int i=1;i<=lena;i++)
{
for(int j=1;j<=lenb;j++)
{
for(int k=1;k<=lenc;k++)
{
if(a[i-1]==b[j-1]&&a[i-1]==c[k-1])
{
dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k-1]+1);
}
else
dp[i][j][k]=max(max(dp[i-1][j][k],dp[i][j-1][k]),dp[i][j][k-1]);
}
}
}
printf("%d\n",dp[lena][lenb][lenc]);
return 0;
}
输出出来和二维一样
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <string.h>
#include <string>
#include <algorithm>
using namespace std;
int dp[300][300][300];
char a[1000];
char b[1000];
char c[1000];
int main()
{
memset(dp,0,sizeof(0));
gets(a);
gets(b);
gets(c);
int lena=strlen(a);
int lenb=strlen(b);
int lenc=strlen(c);
for(int i=1;i<=lena;i++)
{
for(int j=1;j<=lenb;j++)
{
for(int k=1;k<=lenc;k++)
{
if(a[i-1]==b[j-1]&&a[i-1]==c[k-1])
{
dp[i][j][k]= dp[i-1][j-1][k-1]+1 ;
}
else
{
if(dp[i-1][j][k]>dp[i][j-1][k]&&dp[i-1][j][k]>dp[i][j][k-1])
{
dp[i][j][k]=dp[i-1][j][k];
}
else if(dp[i][j-1][k]>dp[i-1][j][k]&&dp[i][j-1][k]>dp[i][j][k-1])
{
dp[i][j][k]=dp[i][j-1][k];
}
else
{
dp[i][j][k]=dp[i][j][k-1];
}
}
}
}
}
string s;
int i=lena,j=lenb,k=lenc;
while(i>=0&&j>=0&&k>=0)
{
if(dp[i][j][k]==dp[i-1][j-1][k-1]+1)
{
s.push_back(a[i-1]);
i--;
j--;
k--;
}
else
{
if(dp[i][j][k-1]>dp[i][j-1][k]&&dp[i][j][k-1]>dp[i-1][j][k])
{k--;
}
else if(dp[i-1][j][k]>dp[i][j-1][k]&&dp[i-1][j][k]>dp[i][j][k-1])
{
i--;
}
else j--;
}
}
reverse(s.begin(),s.end());
cout<<s<<endl;
printf("%d\n",dp[lena][lenb][lenc]);
return 0;
}
下面贴一个网上的代码:
思路:
对于N个子串,找出一个长度最小的串,并分别求出这个最小串的子串,寻找是否剩下的字符串都存在这个子串(子串从大到小找)
不过是不是时间有点多了?空间倒是优化的很好
#include <iostream>
#include <string>
using namespace std;
//将第一个字符串与最短的字符串交换
void swap(string *pStr,int i)
{
string temp;
temp = *pStr;
*pStr = *(pStr + i);
*(pStr + i) = temp;
}
int main()
{
int N;
cout << "请输入N(控制字符串个数):";
cin >> N;
cout << "请输入" << N << "个字符串"<<endl;
string *pStr;
pStr = new string [N];
int i,min;
int maxLen = 1000;
//找出输入的字符串中长度最小的串,并把最小串序号记在min中
for(i = 0; i < N; ++i){
cin >> *(pStr + i);
int len = (*(pStr +i)).length();// *操作符与调用函数的.操作符优先级问题,.优先级高于*,所以必须加上()
if(len < maxLen){
maxLen = len;
min = i;
}
}
swap(pStr,min);
/*
for(i = 0; i < N; ++i)
cout << *(pStr + i) << endl;
*/
int len0 = pStr[0].length();
int j,k,maxlen= 0;
string maxStr;
string tmpStr;
for(i = 0; i < len0 && maxlen <= len0 - i -1; ++i)
{
for(j = 0; j < len0 && maxlen <= len0 - i -j - 1; ++j)
{
tmpStr = pStr[0].substr(i,len0 - j);//对字符串数组中第一个子串,求出其可能的子串值,如果剩余子串长度小于maxlen则不用去求了,for循环中给出了限制
//将子串tmpStr与参与匹配的字符串比较,判断tmpStr是否为剩余串的子串,如果不是则break出循环
for(k = 1; k < N; ++k)
{
string::size_type pos1 = pStr[k].find(tmpStr);
if(pos1 < pStr[k].length())
continue;
else
break;
}
if(k == N)//说明子串tmpStr是其他参与匹配的子串的子串
{
if(tmpStr.length() > maxlen)//tmpStr如果是当前最大的子串,则记录下来
{
maxlen = tmpStr.length();
maxStr = tmpStr;
}
}
}
}
cout << "最大公共子串为:";
cout << maxStr <<endl;
delete []pStr;
return 0;
}