kmp字符串


给定一个字符串 S,以及一个模式串 P

,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模式串 P

在字符串 S

中多次作为子串出现。

求出模式串 P

在字符串 S

中所有出现的位置的起始下标。

输入格式

第一行输入整数 N

,表示字符串 P

的长度。

第二行输入字符串 P

第三行输入整数 M

,表示字符串 S

的长度。

第四行输入字符串 S

输出格式

共一行,输出所有出现位置的起始下标(下标从 0

开始计数),整数之间用空格隔开。

数据范围

1≤N≤105

1≤M≤106

 

输入样例:

3
aba
5
ababa

输出样例:

0 2


#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
int n, m, ne[N];
char p[N], s[M];

int main()// kmp算法由于j每次最多加1,每次向后最少递归1次,故j最多加n次,最多被弹出n次,由此可得时间复杂度为O(n)
{
    scanf("%d%s%d%s", &n, p + 1, &m, s + 1); // 通过+1使得字符串从下表为1的位置开始读入

    for(int i = 2, j = 0; i <= n; i ++ ) // 显然,当i = 1时ne[j] = 0,因为此时只有一个字母,无法自比较
    {
        while(j && p[j + 1] != p[i]) j = ne[j]; // 我们默认j和i-1可以匹配,故当j+1和i无法匹配时,我们就递归的去寻找能匹配的位置
        if(p[j + 1] == p[i]) j ++ ;// 显然i位置最多匹配一个j
        ne[i] = j;// 记录当前位置最大向前匹配到的位置
    }

    for(int i = 1, j = 0; i <= m; i ++ )// 显然,当两字符串进行比较时,要从头开始比较,故i = 1
    {
        while(j && p[j + 1] != s[i]) j = ne[j];// 同理,我们递归的去寻找有可能满足当前位置匹配的最大长度
        if(p[j + 1] == s[i]) j ++ ;// 当可以匹配时,我们将j加1
        if(j == n)// 当完全匹配时
        {
            printf("%d ", i - j);// 记录答案
            j = ne[j];// 递归,继续进行匹配
        }
    }
    puts("");


    return 0;
}

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/280980.html

(0)
上一篇 2022年8月17日
下一篇 2022年8月17日

相关推荐

发表回复

登录后才能评论