KMP

KMP(Knuth-Morris-Pratt)算法是一种线性时间字符串匹配算法。
假设文本\(T\)为一个长度为\(n\)的字符串,模式\(P\)为一个长度为\(m\)的字符串,满足\(m \leqslant n\)。需要在文本中找出所有的匹配点\(s\)使得对任意\(0 \leqslant j < m\)\(T[s+j]=P[j]\)恒成立。
KMP算法在朴素算法的基础上增加了“记忆”功能,在匹配失败时会考虑已匹配的字符串从而进行跳步以降低时间复杂度。模式预处理时间为\(O(m)\),匹配时间为\(O(n)\),总时间复杂度为\(O(m+n)\)
\(T\):文本
\(P\):模式
\(f\):前缀函数,\(f[i]\)表示\(P\)的前\(i\)长度子串的真后缀的最长前缀长度

void getPrefix(string P, vector<int>& f) {
    int m = P.size(), j = 0;
    for(int i = 1; i < m; i++) {
        while(j && P[i] != P[j]) j = f[j];
        f[i + 1] = j += P[i] == P[j];
    }
}
 
 
void find(string T, string P, vector<int>& f) {
    getPrefix(P, f);
    int n = T.size(), m = P.size(), j = 0;
    for(int i = 0; i < n; i++) {
        while(j && T[i] != P[j]) j = f[j];
        if(T[i] == P[j]) j++;
        if(j == m) cout << i - m + 1 << endl;
    }
}

对于\(getPrefix\)函数,\(j\)最多自增\(m-1\)次,每次执行\(j=f[j]\)\(j\)至少减\(1\),且\(j\)恒为非负数,因此\(j=f[j]\)的执行次数最多为\(m-1\)次,从而得出时间复杂度为\(O(m)\)
同理可得\(find\)函数中匹配部分的时间复杂度为\(O(n)\)

posted @ 2020-09-24 21:37  Sakyo  阅读(193)  评论(0)    收藏  举报