AcWing 831. KMP字符串

发布时间 2023-12-04 12:03:13作者: 爬行的蒟蒻

题面:
给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模式串 P 在字符串 S 中多次作为子串出现。
求出模式串 P 在字符串 S 中所有出现的位置的起始下标。

原题链接:831. KMP字符串 - AcWing

核心:next 数组 - 最长相等前后缀

  • next[i] 存储的就是使子串 p[0…i] 有最长相等前后缀的前缀的最后一位的下标[1]
  • 时间复杂度:\(O(m+n)\)
#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;
int a[N], ne[N];

int main()
{
	int n, m;
	string p, s;
	cin >> n >> p >> m >> s;

    //构造模式串p的next数组
    //next[i] 存储的就是使子串 p[0…i] 有最长相等前后缀的前缀的最后一位的下标
    ne[0] = -1; //初始化 next 数组
    for (int i = 1, j = -1; i < n; i++) {
        //当p[j+1] != p[ne[j]+1]时,回退,直到j回到初始值-1
        while (j != -1 && p[i] != p[j + 1]) 
            j = ne[j];
        if (p[i] == p[j + 1]) j++;  //匹配成功,j移向p串下一位
        ne[i] = j;  //更新当前数i的next数组
    }

    //KMP
    for (int i = 0, j = -1; i < m; i++) {
        //匹配失败,j进行回退
        while (j != -1 && s[i] != p[j + 1])
            j = ne[j];
        //匹配成功,j移向p串下一位,继续匹配
        if (s[i] == p[j + 1])   j++;
        if (j == n - 1) {   //全部匹配完毕
            cout << i - j << " ";   //输出当前数组下标
            j = ne[j];  //j回退至上一位,以便下次匹配
        }
    }
}

  1. https://www.acwing.com/solution/content/129372/ ↩︎