http://poj.org/problem?id=3080
kmp是改进版的暴力字符串匹配,明确两个概念——子串和子序列,子串就必须是连续的,子序列不一定,dp有一个问题是最长公共子序列,这里求的是公共子串。
kmp算法最主要的就是一个next数组,一个kmp匹配函数。
这道题目的意思就是输入不超过十个字符串,每个字符串的长度不超过60,然后找出最长的公共子串,如果有好几个子串长度相同,就输出字典序最小的,如果公共子串的长度小于3就不输出了(因为是DNA)
思路:以第一个串为基准,找出它所有的子串,用substr,然后再一重循环,这些个子串分别于剩下的那字符串进行kmp匹配,所以一共是三重循环。
#include<iostream>
using namespace std;
string data[15];
int next[65];
void Get_next(string s,int len)
{
next[0]=-1;
int k=-1;
int i;
for(i=1;i<len;i++)
{
while(k>-1&&s[k+1]!=s[i])
{
k=next[k];
//cout<<k<<" "<<next[k]<<"回溯啦\n";
}
if(s[k+1]==s[i])
k++;
next[i]=k;
}
}
bool kmp(string ptr,int plen,string str,int slen)
{
int k=-1;
for(int i=0;i<plen;i++)
{
while(k>-1&&str[k+1]!=ptr[i])
k=next[k];
if(str[k+1]==ptr[i])
k++;
if(k==slen-1)
return true;
}
return 0;
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int m;
scanf("%d",&m);
int i,j,k;
for(i=0;i<m;i++)
cin>>data[i];
/*Get_next(data[0],data[0].size()); for(i=0;i<data[0].size();i++) cout<<next[i]<<"\n";*/
string ans="";
for(i=1;i<=data[0].size();i++)
{
for(j=0;j<=data[0].size()-i;j++)
{
string op=data[0].substr(j,i);
Get_next(op,op.size());
bool flag=0;
for(k=1;k<n;k++)
{
if(!kmp(data[k],data[k].size(),op,op.size()))
flag=1;
}
if(!flag)
{
if(ans.size()<op.size())
ans=op;
else
if(ans.size()==op.size())
ans=min(ans,op);
}
}
}
if(ans.size()<3)
cout<<"no significant commonalities"<<endl;
else
cout<<ans<<endl;
}
return 0;
}
☝这是一个乱糟糟也得不到正确结果的代码,╭(╯^╰)╮,主要我不想背板子,但是kmp总感觉理解了,还是敲不出来。