poj3080多个字符串找最长公共子串 kmp
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]<<"回溯啦 "; } 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]<<" ";*/ 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总感觉理解了,还是敲不出来。