字符串匹配之KMP(輔助理解KMP算法模板)

假設文本串爲S,模式串爲P
此篇博客只是爲了輔助理解KMP算法,更好的理解KMP算法模板,詳細推導過程並未說明。

1.暴力匹配

for (int i = 0; i < n; i++)
{
    bool flag = true;
    for (int j = 0; j < m; j++)
    {
        if (s[i+j] != p[j])
        {
            flag=false;
            break;
        }
    }
    if(flag) {
    	//匹配成功
    }
}

2.KMP

KMP算法就是通過某些預處理(next數組),使得每次如果Si和Pj不匹配時,不再直接回溯 j 的位置到起始位置,而是回溯到某一箇中間位置(next[j+1]),繼續匹配,且不再回溯 i 的位置。如下圖:
()在這裏插入圖片描述
從上圖應該可以很容易的看出KMP和樸素做法的區別,且如果知道不匹配時j應跳轉的位置(next數組),可以很容易寫出代碼。實際上整個KMP算法代碼很是很簡短的

//匹配過程
for(int i = 0, j = -1; i < m; i++) {    //m表示文本串長度
            while(j != -1 && s[i] != p[j+1]) {  //不匹配則回溯j到ne[j]位置
                j = ne[j];
            }
            if(s[i] == p[j+1]) {    //當前位置匹配,判斷下一個位置
                j++;
            }
            if(j == n-1) {      //匹配到結尾,則再文本串位置找到模式串
                res++;          //res表示模式串在匹配串中個數,在求其他問題時,可變換
                j = ne[j];      //繼續尋找下一個模式串
            }
        }

那麼,整個KMP的重點就是理解next數組了。
在這裏插入圖片描述
上圖中L1, L2,L3, L4,L5表示的字符串序列是綠色框中字符串(字符串序列用線段表示了)。那麼顯然L1 == L2,L3 == L4。同時可以得出L5 == L4。當第 j 個元素不匹配時,變換後的前綴(P0…ne[j])和變換前的後綴相等(從第 j-1 個元素向前取相同長度字符)。
next[j]表示的是P0…j字符串的前綴與後綴相等的最長長度-1(-1是因爲下標從0開始,實質上是最大長度)。
且在求解next[j]時,只和模式串P有關,而和文本串S無關。
理解了next[]數組的含義後,那麼也可以發現求next[]數組本身也是一種字符串匹配得過程。

int ne[MAXN];   //next數組,ne[j]表示P~0...j~字符串的前綴與後綴相等的最長長度-1(-1是因爲下標從0開始,實質上是最大長度)
void init(int n, string p) {  //n表示模板串長度,p表示模板串
    ne[0] = -1;     //-1表示長度爲0
    for(int i = 1, j = -1; i < n; i++) {   //i指向文本串,j指向模式串 
        while(j != -1 && p[i] != p[j+1]) {      
            j = ne[j];
        }
        if(p[i] == p[j+1]) {
            j++;
        }
        ne[i] = j;      
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章