1. 程式人生 > >KMP 字串匹配 學習筆記

KMP 字串匹配 學習筆記

寫在前面:
建議大家先去看洛谷P3375這道題,結合題目食用風味更佳

演算法的原型:暴力樸素演算法(不上程式碼了因為我懶):將原串與用於匹配的串一位一位的匹配,時間複雜度\(O_(nm)\)

改進方法:使用一個next陣列來記錄用於匹配的串的這個點之前的串字首與字尾的最大匹配位數

舉個例子:
\(S_1="ABABABABABC"\)
\(S_2="ABABA"\)

那麼,我們定義一個指標k指向\(S_2\)當前第k個字元,next[k]就是k之前的串中字首字尾的最大匹配位數,根據這一點,我們可以將next[0]初始化為-1(或者是將next[1]初始化為0)

這樣,我們就可以通過\(O_(m)\)

的預處理處理出每一個next,程式碼如下

void pre(char s[]){
    int k=-1,l=strlen(s);
    nxt[0]=-1;
    for(int i=1;i<l;++i){//這裡從1開始是為了匹配字尾
        while(k>-1&&s[k+1]!=s[i])k=nxt[k];
        if(s[k+1]==s[i])k++;
        nxt[i]=k;
    }
    return;
}

演算法核心:利用處理出來的next省去冗餘的掃描,讓時間複雜度成為線性的\(O_(n+m)\)

具體實現:不好說,我水平還不夠,以後補

先上程式碼,可能比較難以理解,請見諒:

void kmp(char s[],char p[]){
    int k=-1;
        int l1=strlen(s),l2=strlen(p);
    for(int i=0;i<l1;++i){//與預處理相似,預處理其實就是自己與自己匹配
        while(k>-1&&p[k+1]!=s[i])k=nxt[k];
        if(p[k+1]==s[i])++k;
        if(k==l2-1){
            printf("%d\n",i-l2+2);
            k=nxt[k];
        }
    }
    return;
}

現在還不是特別明白,先寫在這裡,等哪一天恍然大悟在更新(咕咕咕)