算法基础——KMP字符串匹配

原题连接ios

题目:数组

给定一个模式串S,以及一个模板串P,全部字符串中只包含大小写英文字母以及阿拉伯数字spa

模板串P在模式串S中屡次做为子串出现。指针

求出模板串P在模式串S中全部出现的位置的起始下标。code

输入格式ci

第一行输入整数N,表示字符串P的长度。字符串

第二行输入字符串P。get

第三行输入整数M,表示字符串S的长度。io

第四行输入字符串S。模板

输出格式

共一行,输出全部出现位置的起始下标(下标从0开始计数),整数之间用空格隔开。

数据范围
1 ≤ N ≤ 10^5
1 ≤ M ≤ 10^6

输入样例:

3
aba
5
ababa

输出样例:

0 2

解题代码:

#include <iostream>
#include <cstdio>

using namespace std;
const int N = 100010, M = 1000010;
char p[N], s[M];
int ne[N];
int n,m;

int main(){
    cin >> n >> p + 1 >> m >> s + 1;

    //初始化next数组(寻找模板串中最长的公共先后缀)
    for(int i = 2, j = 0; i <= n; i++){
        while(j && p[i] != p[j + 1]) j = ne[j]; //前缀与后缀匹配失败,使j回退到以前找到的公共先后缀的长度的位置,直到 p[i] 和 p[j + 1]匹配 或 j 回退到了起点(0的位置)。
        if(p[i] == p[j + 1]) j++;   //前缀的i下标元素和后缀的j+1下标元素匹配成功,并继续匹配下一个
        ne[i] = j;  //前i个数中的最长公共先后缀的长度为j,标记j的位置,以用来以后将j回退
    }
    //开始匹配
    for(int i = 1, j = 0; i <= m; i++){
        while(j && s[i] != p[j + 1]) j = ne[j];
        if(s[i] == p[j + 1]) j++;
        if(j == n){
            printf("%d ", i - n);
            j = ne[j];  //j指针回退,继续寻找下一个能匹配的位置
        }
    }

    return 0;
}
相关文章
相关标签/搜索