这两题都是找出所给字符串的最长公共子串。
本来是简单的枚举,直接枚举第一个串s[0]的所有子串(从长到短),看是否是其他所有字符串的子串,若是,则只需再将s[0]的相同长度的其他子串检测一遍就好了。
再找满足条件的子串中的最小串就很简单了(其实检测过程中比较一下即可)。但该方法效率太低,超时。
怎样才能高效呢?
具体是这样的:
枚举s[0]的所有后缀,以后缀为匹配串,将其与其他串匹配。在匹配过程中,即调用KMP()函数时,可以根据 匹配过程中的J 的值来确定其他串与该后缀的最大匹配,以此来确定该后缀能与其他字符串的最大匹配的前缀,(有点晕的话看代码吧,可能容易理解点)然后取出前缀。由此即可找到所求最长公共子串。
代码:
#include <stdio.h>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int h,n,m,p[101],MAX;
string b,s[4000];
void getp()
{
p[0]=-1;
int j=-1;
for(int i=1;i<m;i++){
while(j>-1&&b[j+1]!=b[i]) j=p[j];
if(b[j+1]==b[i]) j+=1;
p[i]=j;
}
}
void kmp()
{
m=b.size();
MAX=200;
getp();
for(int k=1;k<h;k++)
{
int ma=0;
int i,j;
j=-1;
n=s[k].size();
for(i=0;i<n;i++)
{
while(j>-1&&b[j+1]!=s[k][i]) j=p[j];
if(b[j+1]==s[k][i]) j+=1;
if(j==m-1)
{
ma=m;break;
//j=p[j];
}
if((j+1)>ma)ma=j+1;
}
if(ma<MAX)MAX=ma;
}
}
int main()
{
string re1,re2;
int _size;
while(cin>>h&&h)
{
_size=0;
for(int i=0;i<h;i++)
cin>>s[i];
int len=s[0].length();
for(int i=0;i<len;i++)
{
b=s[0].substr(i,len-i);
kmp();
if(MAX>_size)
{
_size=MAX;
re1=s[0].substr(i,_size);
}
else if(MAX==_size)
{
re2=s[0].substr(i,MAX);
if(re2<re1)re1=re2;
}
}
if(_size==0)cout<<"IDENTITY LOST\n";
else cout<<re1<<endl;
}
return 0;
}
POJ 3080 Blue Jeans
代码:
#include <iostream>
#include <string>
using namespace std;
const int len=60;
int num,m,p[60],MAX;
string s[10],b;
void getp()
{
p[0]=-1;
int j=-1;
for(int i=1;i<m;i++){
while(j>-1&&b[j+1]!=b[i]) j=p[j];
if(b[j+1]==b[i]) j+=1;
p[i]=j;
}
}
int kmp()
{
int curml;
m=b.size();
getp();
MAX=60;
for(int k=1;k<num;k++)
{
curml=0;
int j=-1;
for(int i=0;i<len;i++)
{
while(j>-1&&b[j+1]!=s[k][i])j=p[j];
if(b[j+1]==s[k][i])j++;
if(j+1==m)
{
curml=m;
break;
}
if(j+1>curml)curml=j+1;
}
if(curml<MAX)MAX=curml;
}
return MAX;
}
int main()
{
int t,k,mlen;
string str1,str2;
cin>>t;
while(t--)
{
mlen=0;
str1="";
cin>>num;
for(int i=0;i<num;i++)
cin>>s[i];
for(int i=0;i<len;i++)
{
b=s[0].substr(i,len-i);
k=kmp();
if(k>mlen)
{
mlen=k;
str1=s[0].substr(i,k);
}
else if(k==mlen)
{
str2=s[0].substr(i,k);
if(str2<str1)str1=str2;
}
}
if(str1.length()<3)
cout<<"no significant commonalities"<<endl;
else cout<<str1<<endl;
}
return 0;
}