KMP算法詳解

一、 KMP算法解決什麼問題?

KMP解決的是用線性複雜度在主串中查找第一次出現模式串的下標。
如果使用普通方法,那就是用二重循環搜索,時間複雜度爲 O(M*N)。M爲主串長度,N爲模式串長度。

【舉例子】
使用KMP算法,我們可以用 O(N) 的時間複雜度在主串"abcdef@abga@cd"中查找模式串 “abga”。

二、理解KMP算需要理解哪些部分?

  1. 前綴、後綴概念
  2. next[N]next[N]數組
  3. next[N]next[N]數組的迭代求法
  4. 根據next[N]next[N]數組移動指向模式串的指針匹配主串

三、 拆分講解

1. 前後綴概念、next[N]數組的意義

【舉例子】
字符串str="babdefbab"的不同長度的前綴、後綴如表1.。

長度 前綴 後綴
1 b b
2 ba ab
3 bab bab
4 babd fbab
5 babde efbab
6 babdef defbab
7 babdefb bdefbab
8 babdefba abdefbab
9 babdefbab babcdefbab

其中相同長度的前綴和後綴相等的有b、bab、babdefbab。
相同長度的真前綴和真後綴相等的有b、bab。其中長度最長的相等真前後綴爲bab。
【概念】
根據上面的例子我們可以抽象前綴、後綴的概念

  • 前綴指字符串的任意首部。 真前綴指不包含本身字符串的任意首部,字符串的真前綴長度要小於字符串的長度。
  • 後綴指字符串任意尾部。字符串的真後綴的長度要小於字符串的長度。
2. next[N]next[N]數組的意義

【概念】
next[i]next[i]表示strstr的下標爲 00i1i-1 的子串的最長的相等的真前後綴的長度。next[i]next[i]的範圍爲[-1,N-1]$。

【舉例子】 仍然用字符串str="babdefbab"舉例

i 0 1 2 3 4 5 6 7 8
next[i] -1 0 0 1 0 0 0 1 2
3. next[N]next[N]數組的迭代求法
  • 先看代碼
void nextSolution(int *next,int len,char *pattern){
    int index=0,k=-1;
    next[0]=k;
    while(index<len-1){
        if(k==-1||pattern[index]==pattern[k]){//注意next[0]=-1的特例
            next[++index]=++k;
        }else{
            k=next[k]; //調整k
        }
    } 
}
  • 看圖解釋
    初始值 i=0,next[i]=0,k=next[i]i=0,next[i]=0,k=next[i]
  1. k==1k==-1時,next[i+1]=k+1。
    在這裏插入圖片描述
  2. str[i]=str[k]str[i]=str[k]時,next[i+1]=k+1。
    在這裏插入圖片描述
  3. str[i]str[k]str[i] \ne str[k]時,迭代k=next[k]。
    在這裏插入圖片描述
4. 根據next[N]next[N]數組移動指向模式串的指針匹配主串
  • 先看代碼
int kmp(char * haystack, char * needle){
    
    const int len_ned=strlen(needle);
    if(len_ned==0)//模式串爲""默認返回0
        return 0;
    const int len_hay=strlen(haystack);
    if(len_ned>len_hay)//模式串長度大於主串長度
        return -1;
    
    int next[len_ned];
    nextSolution(next,len_ned,needle);
    
    int index_hay=0,index_needle=0;
    while(index_hay<len_hay&&index_needle<len_ned){
        if(index_needle==-1||haystack[index_hay]==needle[index_needle]){//注意next[0]=-1的特例
            index_hay++;
            index_needle++;
        }else{
            index_needle=next[index_needle];
        }
        if(index_needle==len_ned){
       	 	return index_hay-len_ned;
    }
    
 	return -1;
}
  • 看圖講解
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章