字符串匹配之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;      
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章