KMP算法

字符串匹配中常常會用到KMP算法。它求解的問題類型是:字符串匹配。給你兩個字符串,尋找其中一個字符串是否包含另外一個字符串,若是包含,返回包含的起始位置。 ios

咱們通常的作法是:將一個字符串(長度爲n,模式串)放在另外一個字符串(長度爲m,主串)開始的位置,而後依次比較,若是有不匹配的字符,就將字符串日後移一位,而後依舊從頭開始比較。直到找到徹底匹配的位置,返回。遍歷順序從0到m-n,每次遍歷,都要比較n(最多)次,因此複雜度近似爲O(m*n);算法

而咱們今天說的這個KMP算法,能夠達到O(m+n)的複雜度。數組

算法基本思想:每次當匹配失敗時,沒有必要就移動一位,由於前面可能有已經匹配的字符了。若是模式串當前的字符存在公共先後綴,那麼我能夠對於每個模式串事先計算出模式串的內部匹配信息,在匹配失敗時最大的移動模式串,以減小匹配次數。spa

注意最長前綴:是說以第一個字符開始,可是不包含最後一個字符code

KMP有個next數組,用來存放模式串中內部的匹配信息。舉個例子,好比模式串爲ababaca,長度是7,因此next[0],next[1],next[2],next[3],next[4],next[5],next[6]分別計算的是 aababaababababaababacababaca的相同的最長前綴和最長後綴的長度。因爲aababaababababaababacababaca的相同的最長前綴和最長後綴是「」,「」,「a」,「ab」,「aba」,「」,「a」,因此next數組的值是[-1,-1,0,1,2,-1,0],這裏-1表示不存在,0表示存在長度爲1,2表示存在長度爲3。這是爲了和代碼相對應。blog

當求出模式串的next數組以後,咱們就要進行KMP算法的匹配了。ci

#include <iostream>
#include <string>
#include <vector>
using namespace std;
void cal_next(string str,vector<int>&next)
{
    int len=str.size();
    next[0]=-1;
    int k=-1;
    for(int i=1;i<len;i++)
    {
        while(k>-1 && str[k+1]!=str[i])
        {
            k=next[k];
        }
        if(str[k+1]==str[i])
        {
            k++;
        }
        next[i]=k;
    }
}
int KMP(string str,string ptr,vector<int>&next)
{
    int s=0,p=0;
    while(s<str.size() && p<ptr.size())
    {
        if(str[s]==ptr[p])
        {
            s++;
            p++;
        }
        else
        {
            if(p==0)
                s++;
            else
                p=next[p-1]+1;
        }
    }
    return (p==ptr.size())?(s-ptr.size()):-1;
}
int main()
{
    string str,ptr;
    cin>>str>>ptr;
    vector<int> next;
    next.resize(ptr.size(),0);
    cal_next(ptr,next);
    cout<<KMP(str,ptr,next)<<endl;
    return 0;
}

程序的關鍵在於如何理解next的做用,以及如何維護它。字符串

相關文章
相關標籤/搜索