KMP笔记

首先对字符串首先要求一个前缀函数\(\pi[i]\)\(\pi[i]\)简单来说就是子串\(s[0\dots i]\)最长的相等的真前缀与真后缀的长度。

vector<int> prefix_function(const string &s) {
    int n = s.size();
    vector<int> pi(n);
    for (int i = 1, j; i < n; i++) {
        j = pi[i - 1];
        while (j > 0 && s[i] != s[j]) j = pi[j - 1];
        if (s[i] == s[j]) j++;
        pi[i] = j;
    }
    return pi;
}

然后就是 KMP 算法的实现有两种,两种做法效率实际上一样的

vector<int> kmp(const string &text, const string &pattern) { // pattern 在 text 中出现的位置
    string cur = pattern + '#' + text;
    int n = text.size(), m = pattern.size();
    vector<int> v, lps = prefix_function(cur);
    for (int i = m + 1; i <= n + m; i++)
        if (lps[i] == m) v.push_back(i - 2 * m);
    return v;
}

除了这样做之外,还有一种做法是求不重复的匹配位置

vector<int> kmp(const string &text, const string &pattern) {
    vector<int> v, lps = prefix_function(pattern);
    for (int i = 0, j = 0; i < text.size(); i++) {
        while (j && text[i] != pattern[j]) j = lps[j - 1];
        if (text[i] == pattern[j]) j++;
        if (j == pattern.size())
            v.push_back(i - j + 1), j = 0;
    }
    return v;
}
posted @ 2023-06-01 22:21  PHarr  阅读(11)  评论(0编辑  收藏  举报