字符串_kmp算法

kmp算法的核心就是pi数组,pi[i]所表示的是在字符串s的子串s[0-i]中,最长的真前缀与后缀相等的长度。
pi数组的求法:

点击查看代码
vector<int> pi(n);
    for (int i = 1; i < n; i++) {
        int j = pi[i - 1];
        while (j > 0 && s[i] != s[j]) {
            j = pi[j - 1];
        }
        if (s[i] == s[j]) {
            j++;
        }
        pi[i] = j;
    }
大致可以理解为每次求到下一个位置的pi值的时候,看前缀的新增位置与后缀的新增位置是否相同,如果不相同还需要减小pi值。 借用这个pi值可以求很多东西,比如要求字符串s所有的前后缀相同,就找到pi[n -1],要找下一位的话,考虑已经确定的前后缀相同的情况,以此类推求下去,代码如下
点击查看代码
int bin = n;
    vector<int> pre;
    pre.push_back(n);
    while (bin) {
        if (!pi[bin - 1])
            break;
        pre.push_back(pi[bin - 1]);
        bin = pi[bin - 1];
    }
pi数组还可以用来求该字符串的前缀在字符串中出现了多少次,只要pi[i]大于等于该前缀的长度就代表在i往前的位置中出现了该前缀 直接给出该题目完整代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;


int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    string s;
    cin >> s;
    int n = s.size();
    // cout << s << ' ' << n;
    vector<int> pi(n);
    for (int i = 1; i < n; i++) {
        int j = pi[i - 1];
        while (j > 0 && s[i] != s[j]) {
            j = pi[j - 1];
        }
        if (s[i] == s[j]) {
            j++;
        }
        pi[i] = j;
    }
    int bin = n;
    vector<int> pre;
    pre.push_back(n);
    while (bin) {
        if (!pi[bin - 1])
            break;
        pre.push_back(pi[bin - 1]);
        bin = pi[bin - 1];
    }
    cout << pre.size() << "\n";
    vector<int> cnt(n + 1);
    for (int i = 0; i < n; i++) {
        cnt[pi[i]]++;
    }
    for (int len = n; len > 0; len--) {
        cnt[pi[len - 1]] += cnt[len];
    }
    for (int i = pre.size() - 1; i >= 0; i--) {
        cout << pre[i] << ' ' << cnt[pre[i]] + 1 << "\n";
    }

    return 0;
}

posted @ 2026-07-14 17:52  hybrz  阅读(0)  评论(0)    收藏  举报