KMP算法(uva 1328)

来源:互联网 发布:全球购海淘宝 编辑:程序博客网 时间:2024/06/01 08:59
提问:假设存在一个长度为n的字符串T,模板是一个长度为m的字符串P,且m<=n。求出所有模板在字符串中的匹配点。
         匹配点即为:满足T[i]=P[0],T[i+1]=P[1],.........,T[i+m-1]=P[m-1]的点i;
         最简单的办法就是挨个找,如果有不对的,就换下一个匹配点。时间复杂度最大为O(m*(n-1)),不是很理想。
         于是,我们就想到了能否根据模板自身的规律减少时间复杂度?KMP算法就诞生了!
         KMP算法最关键的就是一个失配函数F(i),什么就做失配函数呢?
         F(i)代表如果你在对比模板第i位时,失配了也就是不一样了,我们要跳到与模板的第 F(i)位比较,而不是直接重新开始比较。
给出一个建立失配函数的模板:
  
void getFail (char *P,int *f){ //构建失配函数 f为失配函数 P为模板串  int m=strlen(P);  f[0]=f[1]=0;  for (int i=1;i<m;i++){    int j=f[i];    while (j&&P[i]!=P[j]) j=f[j];    f[i+1]=P[i]==P[j]?j+1:0;  }}


样例:  零 一 二 三 四 五 六 七 八 九 十 十一

 p[i]  A B R A C A D A B R A                                                                                 

  f[i]   0   0   0   0   1   0   1   0   1   2   3   4

         在失配函数知道的基础上我们写搜索函数就很好写了:
下面是我的模板:

int find(char *T,char *P,int *f) {  //P为模板串 T为比较串 f为失配函数    int n=strlen(T);    int m=strlen(P);    getFail(P,f);    int j=0;    for (int i=0;i<n;i++){      while (j&&P[j]!=T[i]) j=f[j];     //按照失配函数调整比较的位置      if (P[j]==T[i]) j++;      if (j==m) ans++;   //找到子串 输出所在位置    }    return 0;}


给道题加深对F(i)函数的理解:  uva 1328    
     根据我们求F(i) 函数的方法,可以看出,如果f(i)>0 代表 i前面的 f(i)个字符与前i-1个字符一样。
    如果能形成循环必有 K*(i-F(i))=i;(K为整数) 仔细想想,必然成立;
我的代码:

#include <cstdio>
const int maxn = 1000000+10;
using namespace std;
char s[maxn];
int f[maxn];
int main (){
  int n,kase=0;
  while (scanf("%d",&n)!=EOF&&n){
    scanf("%s",s);
    f[0]=f[1]=0;
    for (int i=1;i<n;i++){
      int j=f[i];
      while (j&&s[i]!=s[j]) j=f[j];
      f[i+1]=s[i]==s[j]?j+1:0;
    }
    printf("Test case #%d\n",++kase);
    for (int i=2;i<=n;i++){
      if (f[i]>0&&i%(i-f[i])==0) printf("%d %d\n",i,i/(i-f[i]));
    }
    printf("\n");
  }
  return 0;

}



为什么我这篇文章发的就这么费劲呢?T_T 深夜发,不管如何就是保存不成功。白天发也保存不成功,成功一次后发现,重复发了n回。又要重新删除。

0 0
原创粉丝点击