字符串KMP算法小结

做了几道KMP的简单题,有些需要记下来的关键点,以供以后查看。

先是KMP的模板:

const int maxn = 1000000+10;
char s1[maxn],s2[maxn];
int len1,len2,next[maxn];
void getnext()
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<len2)
    {
        if(j==-1||s2[i]==s2[j])
        {
            i++,j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
int kmp()
{
    int i=0,j=0,sum=0;
    while(i<len1&&j<len2)
    {
        if(j==-1||s1[i]==s2[j])
            i++,j++;
        else j=next[j];
        if(j==len2)
        {
            sum++;
            j=next[j];
        }
    }
    return sum;
}

 

1.其中要先把数组放在外面做全局变量,如果遇到数字的话,就把数组类型改成int 型,长度也放在外面,数组大小的话看题意;


2.s1[maxn]为主串,s2[maxn]为模式串,函数getnext();得到的next[maxn]是只关于模式串的s2[maxn],所以是s2[i]==s2[j];

3.对于不同的题:(实际上要改的就是kmp函数中后面关于j的。)

(1)要求找相同的,例如:abcd主串,ab模板串,sum会为1,所以主函数就if(kmp())printf("YES\n");

  例子:HDU2203    解题报告:http://www.cnblogs.com/wgl20130409/p/3258393.html

(2)要求找多少个,可以重叠,例如:azazaza主串,zaz模板串,有3个,就用上面的就行,直接输出sum就行;

  例子:HDU1686   解题报告:http://www.cnblogs.com/wgl20130409/p/3264798.html

(3)要求找多少个,但不可以重叠,就把上面kmp函数中后一个j=next[j],改为j=next[j]+j;就行;

  例子:HDU2087   解题报告:http://www.cnblogs.com/wgl20130409/p/3258261.html

(4)要求找到一个,输出首个的位置(使得位置最小就是第几个),这样的话,就不用sum了,利用j;在kmp 函数循环完,看j的大小,如果小于len2,就没有,反之 返回i-len2+1.

  例子:HDU1711   解题报告:http://www.cnblogs.com/wgl20130409/p/3264761.html

差不多就是这样,万变不离其宗,不理解不要紧,只要记住模板,时间长了就慢慢明白。。。。。

加油!!!!!!!!!

今天上午又看了一上午的KMP,总算是把next[]函数弄懂了,但怎么和代码结合起来,还需要长久的“悟”才行。。                                                         

一般KMP有两种,我上面的代码next[]是代码比较简单的,但效率比另一种要低。                                                                                            

next[i]=x表示在第i+1个元素的时候他前面的有没有相同的,例子:ababc,对于第5个元素c来说,它的前两项与开始两项相同,所以next[4]=2;这实际上有什么作用呢??

看代码:if(j==-1||s1[i]==s2[j])
            i
++,j++;
       
else j=next[j];
简单说,就是  主串为aabaabxxxxx,模板串为aabaaa,原始的比较是一个一个比,如果不匹配就向后挪一个,但如果在模式串中有重复的就会浪费时间,如上当比到

aabaabxxxxx                                                                                                                                                                                                                              

aabaaa                                                                                                                                                                                                                 

012345                                                                                                                                                                                                                           

第6个不一样,说明第6个前面的两个aa和主串上的对应位置一样,而模板串中第6个前面的2个和开始2个一样,那么就可以直接让开始跳过去:

aabaabxxxxx    

     aabaaa    这就是next[5]=2;的作用;

那么怎么得到next[]函数呢??就是看模板串。

        012345678

例子:ababcaabc    设next[0]=-1;然后看第2个元素,(实际上是第i+1个),定义j=0,j<i;为元素i之前的j个元素,然后让元素i之前的j个元素和开始j个元素比较是否相同,直到不同,next[i]=j;所以得到-1 0 0 1 2 0 1 1 2

 

今天下午又给同学讲了一下,又有新的理解。就是关于怎么实现的上面的思想。确切的说是怎么理解代码。

关于next[]的函数getnext()中if(j==-1||s2[i]==s2[j])的条件,j==-1是初始化进的条件,也是当连续与前面不相等的情况下让进的条件,例子:abcabdaxxxx,当后面的xxxx时,j就等于-1;

然后是其中的next[i]=j;因为比如说上面的例子,当i等于5时,基于理论,此时应该j=2;而j在本函数中有两个作用,一个是计数,一个是走位置比较(就是当做下标);

 对于理解getnext()函数做的输出调试;

void getnext()
{
    int i=0,j=-1;
    next[0]=-1;
    while(i<len2)
    {
        if(j==-1||s2[i]==s2[j])
        {
            i++,j++;
            next[i]=j;
            printf(" %d %d  ",i,j);
//输出的就是i,j的位置;
}
else { j=next[j]; printf("\n"); printf("** %d %d **",i,j); } //输出的i是下标,j的位置
} }

 

                                                            
                                                                                                                                                                                                          

posted @ 2013-08-17 17:16  拼搏今朝 努力奋进  阅读(247)  评论(0)    收藏  举报