kmp算法学习

  1. kmp算法可以用作匹配字串问题的朴素算法的改进,相对与朴素的查找O(n^2)的时间复杂度,kmp算法只需要大致为O(n),大大提升了查找速度。
  •        kmp算法区别于朴素查找的算法的不同点就是它可以更高效的回溯比较。
  • kmp算法学习

     

     上图第六个字母不同,朴素做法是从主串的第二个开始,重新遍历,而kmp算法更加高效。

  •  kmp算法学习

     

     它跳过了其中不可能的字符遍历,节省了时间,它只对子串进行了回溯,我们注意到不同的是‘=’和‘c’,主串仍然将从这个位置继续向后遍历。

  • kmp算法学习

     

     这是直观上的比较


     

     

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

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

         kmp算法学习

 

 

         3.求next数组

          此为图示:

kmp算法学习

 

 

 

 

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)(我不会,不好意思,网上的太长了,也许以后会看看再补上)

  

              

 

上一篇:KMP(KMP字符串)


下一篇:1089 狼人杀-简单版 (20 分)