学习字符串处理之KMP算法

来源:互联网 发布:淘宝大学vip课程多少钱 编辑:程序博客网 时间:2024/05/21 08:08

概念一:“前缀包含子串”
前缀包含子串是指,字符串前缀子串中的所有非空非自身子串。
contain_sub_strings = {s|s等于前缀子串 /\s不是前缀子串}(要好好想想理解一下)。
例如:对于字符串”aaaa*a”,其前缀子串”*aaaa“的包含子串的集合就是{“a”, “aa”, “aaa” }(这个例子不是很好,如果您有好的例子,欢迎您提供)。
下面分析字符串匹配的过程,设原串从某一起始地址i开始匹配到了模式串的第m个字符,既是ori[i … i + m] = pat[0 .. m],若此时ori[i + m +1] 与 pat[ m + 1] 不匹配,那么该接下来该怎样处理呢?—————–问题Q
朴素方法的解决方案是,从ori[i+1]开始在ori[i+1 … ]中查找模式串;
这种方法几乎完全没动脑子,是一种极度傻瓜的办法(不可否认,傻瓜的办法总是正确的),下面让我们开始动动脑子:
1)假设pat[0 … m]前缀包含子串的集合 = {“pat[0]”},此时我们很容易就可以知道pat[0]不在pat[1…m]中,那么“问题Q”的答案是什么呢?很简单,从ori[i + m + 1]开始查找模式串,因为ori[i+1 … i + m ] = pat[1 … m] ,也就是说从ori[i + 1]到ori[i + m]为止没有一个字符能与pat[0]匹配;
2)进一步分析,让情况复杂一点,pat[1 … m]中有很多个字符等于pat[0],设这些字符下标的集合等于A0 = {i | pat[i] = pat[0] /\ 1 <= i <= m},记 k = min (A0);
那么这时该怎么回答“问题Q”呢?答案就是从ori[i + k ]开始找模式串, 理由和 1) 一样ori[i+1 .. i +k-1]中没有一个字符能和pat[0]匹配;
3)前缀包含子串集合中的最长子串和最短子串应该选哪一个作为决策的根据?最长子串。
设最长和最短前缀包含子串分别为gs 和 ls,
记A_minlen = {il|pat[il…] = ls /\ 1<=il },
A_maxlen = {ig|pat[ig…] = gs /\1<=ig} ,
k_minlen = min (A_minlen),k_maxlen=min(A_minlen);

分析如下:
和2)一样,我们根据最长子串和最短子串分别可以找到k_maxlen 和k_minlen,k_minlen <= k_maxlen(假设k_minlen > k_manlen,很容易就可以得到最短子串不是最长子串的前缀,根据包含子串的定义这是不可能的),对于任意任意的il,(il

#include<stdio.h>#include<malloc.h>#include<string.h>//求next数组void next_pat(int next[],char parten[],int n){    int i,t,t1;    char temch,temch1;    int *f= (int*)malloc((n+1)*sizeof(int));    f[0] = next[0]=-1;    f[1] = next[1]=0;    for(i=2;i<=n;i++)    {        temch=parten[i-1];        temch1 = parten[i];        t = f[i-1];        while(t>=0 && temch!= parten[t])        {            t = f[t];        }        t1 = f[i] = t + 1;        //优化处理        while(0<=t1 && parten[t1] == temch1)        {            t1 = f[t1];        }        next[i] = t1;    }    free(f);    //printf("%d\n",next[n]);}//统计模式串出现的次数int counter(char *ori,char *par,int *next,int len,int n){    int count=0;    int i,j;    j=0;    i=0;    while(i<len)    {        if(ori[i]==par[j])        {            if(j==n-1)            {                j=next[n];                if(j<0)                {                    j=0;                }                count++;            }            else            {                j++;            }            i++;        }        else        {            j=next[j];            if(j<0)            {                j=0;                i++;            }        }    }    return count;}int main(){    int n;    char ori[1000005],par[10005];    int next[10005];//  FILE *in = NULL;//  in = fopen("input.txt","r");//  fscanf(in,"%d",&n);    scanf("%d",&n);    int i;    int re;    int len;    for(i=0;i<n;i++)    {//      fscanf(in,"%s",par);//      fscanf(in,"%s",ori);        scanf("%s%s",par,ori);        len=strlen(par);        next_pat(next,par,len);        re=counter(ori,par,next,(int)strlen(ori),len);        printf("%d\n",re);    }//  fclose(in);    return 0;}
0 0
原创粉丝点击