编程语言
首页 > 编程语言> > kmp算法学习

kmp算法学习

作者:互联网

  1. kmp算法可以用作匹配字串问题的朴素算法的改进,相对与朴素的查找O(n^2)的时间复杂度,kmp算法只需要大致为O(n),大大提升了查找速度。

         2. 最长相等前后缀:顾名思义就是一段长串中前后相同长度的部分是完全一样的,比如"aba",这一段最长相等前后缀就是a,它的长度为一,我们注意到上述图示中,第一次字符不匹配时的主串为“abccab”(我截取前一部分),它的最长相等前后缀为"ab",长度为2,我们注意到字串便是回溯到了这个位置。

         所以我们要做的就是求出每一个字符的最长相等前后缀,并将他保留到数组,记作next数组,我们定义它表示next[i]这个位置前的最长相等前后缀长度,比如"ab",那么next[1]=0。

         

 

 

         3.求next数组

          此为图示:

 

 

 

 

char s[N];
int next[N];
void getnext(char s[]){
    int i=0,j=-1,len=strlen(s);
    next[0]=-1;//第一个字符没有最长相等前后缀所以赋值-1
    while(i<len-1){//注意到下方i++,所以i还是会到len-1
        if(j==-1||s[i]==s[j]) i++,j++,next[i]=j;//保留最长相等前后缀
        else j=next[j];//重新匹配最长相等前后缀
    }
}

 

  

  

        4.KMP

char s[N],t[N];//t是子串
int kmp(char s[]){
    getnext(s);
    int len1=strlen(s),i=0,j=0,d=0;
    int len2=strlen(t);
    while(i<len1&&j<len2){
        if(j==-1||s[i]==t[j]) i++,j++;//相同继续匹配
        else j=next[j];//不同回溯字串
    }
    if(j==len2) reutrn i-len2;//返回下标
    else return -1;//未找到
    return d;
}

 

  

         5.不过kmp算法仍有可改进之处,那便是next数组,比如对于"aaabaaassssss","aaacbbb",当比较到第四个时,字串回溯为2,仍然是a,这就有待改进,我们可以优化next保存的值,尽可能跳过这种多余比较。

   void getnext(char s[]){    int i=0,j=-1,len=strlen(s);

 next[0]=-1;
    while(i<len-1){
        if(j==-1||s[i]==s[j]){
            i++,j++;
            if(s[i]!=s[j])
                next[i]=j;//这等于原来的next[i]=j,代表着字串返回后相同,保存长度
            else next[i]=next[j];//不同的的话就保存就再回溯一次的长度
        }//为什么你不写一个直接保留最终位置的next呢?(我也不会,这还是看的别人代码。。。)
        else j=next[j];
    }
}

 

  6.算法复杂度,假设主串长度n,字串为m,朴素做法最好情况为O(n),最坏为O(n*m);

           kmp,假设主串长度n,字串为m,求next数组的时间复杂度为O(m),总时间复杂度为O(m+n)(我不会,不好意思,网上的太长了,也许以后会看看再补上)

  

              

 

标签:主串,int,next,学习,后缀,算法,kmp
来源: https://www.cnblogs.com/-Icarus/p/15890412.html