KMP字符串

KMP

已知字符串 \(l1\) 和 模式串 \(l2\)
KMP的主要做法为:建立一个\(next\)数组,记录与以\(l2[0]\) 开头, \(l2[i]\)结尾的一段字符串的最长与后缀相同的前缀最后一个字符的下标。

举个栗子

参考代码

void getne(string s2, int l2)
{
    ne[0] = -1;
    int p1 = 1, p2 = -1; // p1, p2 分别是 两个指针
    for (; p1 < l2; p1++)
    {
        while(p2 >= 0 && s2[p2 + 1] != s2[p1]) // 不同就跳到与此后缀相同的前缀
            p2 = ne[p2];
        if(s2[p2 + 1] == s2[p1]) // 相同就向前
            p2++;
        ne[p1] = p2; // 记录 ne
    }
}

建好\(next\)数组后,与字符串\(l1\)匹配, 用两个指针\(p1, p2\)遍历字符串, \(l1[p1], l2[p2 + 1]\)不匹配则缩短长度;
匹配则两个指针同时向前移,当长度为\(l2\)的长度时, 用ans数组存储答案。

举个栗子

参考代码

void kmp(string s1, string s2)
{
    int l1 = s1.length(), l2 = s2.length(); // l1, l2 分别是 s1 和 s2 的长度
    int p1 = 0, p2 = -1; // p1, p2 分别是 两个指针
    getne(s2, l2); // 拿到 ne(next简称) 数组
    for (; p1 < l1; p1++)
    {
        while (p2 != -1 && s1[p1] != s2[p2 + 1]) // 不同就跳到与此后缀相同的前缀
            p2 = ne[p2];
        if (s1[p1] == s2[p2 + 1]) // 相同就向前
            p2++;
        if (p2 == l2 - 1) // 记录答案
        {
            ans[++pos] = p1 - p2;
            p2 = ne[p2];
        }
    }
}

例题

题目传送门

完整代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int ne[N], pos = 0, ans[N];
void getne(string s2, int l2)
{
    ne[0] = -1;
    int p1 = 1, p2 = -1; // p1, p2 分别是 两个指针
    for (; p1 < l2; p1++)
    {
        while(p2 >= 0 && s2[p2 + 1] != s2[p1]) // 不同就跳到与此后缀相同的前缀
            p2 = ne[p2];
        if(s2[p2 + 1] == s2[p1]) // 相同就向前
            p2++;
        ne[p1] = p2; // 记录 ne
    }
}
void kmp(string s1, string s2)
{
    int l1 = s1.length(), l2 = s2.length(); // l1, l2 分别是 s1 和 s2 的长度
    int p1 = 0, p2 = -1; // p1, p2 分别是 两个指针
    getne(s2, l2); // 拿到 ne(next简称) 数组
    for (; p1 < l1; p1++)
    {
        while (p2 != -1 && s1[p1] != s2[p2 + 1]) // 不同就跳到与此后缀相同的前缀
            p2 = ne[p2];
        if (s1[p1] == s2[p2 + 1]) // 相同就向前
            p2++;
        if (p2 == l2 - 1) // 记录答案
        {
            ans[++pos] = p1 - p2;
            p2 = ne[p2];
        }
    }
}
int main()
{
    int t;
    string a = "", b = "";
    cin >> t;
    for(int i = 1; i <= t; i++)
    {
        char c;
        cin >> c;
        a += c;
    }
    cin >> t;
    for(int i = 1; i <= t; i++)
    {
        char c;
        cin >> c;
        b += c;
    }
    kmp(b, a);
    for(int i = 1; i <= pos; i++)
    {
        cout << ans[i] << ' ';
    }
    return 0;
}

实在不理解的话, 看这里

posted @ 2025-11-03 14:23  ly_fish  阅读(0)  评论(0)    收藏  举报