ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AcWing 831. KMP字符串

2021-06-25 23:01:41  阅读:158  来源: 互联网

标签:831 int ne 后缀 maxn 字串 KMP 字符串 AcWing


按照惯例,

今回是MOGE子镇楼。

今天是KMP算法,感觉理解还是不太扎实,写篇博客记录一下。

 

题目:

给定一个模式串 SS,以及一个模板串 PP,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模板串 PP 在模式串 SS 中多次作为子串出现。

求出模板串 PP 在模式串 SS 中所有出现的位置的起始下标。

输入格式

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

第二行输入字符串 PP。

第三行输入整数 MM,表示字符串 SS 的长度。

第四行输入字符串 SS。

输出格式

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

数据范围

1≤N≤1051≤N≤105
1≤M≤1061≤M≤106

输入样例:

3
aba
5
ababa

输出样例:

0 2

暴力我们就不解释了,直接进入KMP。

KMP就是对字符串进行一系列匹配,从而减少不必要的操作,减小复杂度。

如何匹配呢,这就是我们的问题。KMP的做法就是找到字串的最大相同前后缀,从而进行匹配。

我们先写出我们能写出的代码:

#include<cstdio>
const int maxn = 1e5 + 10;
char S[maxn*10], P[maxn];
int main()
{
    int ls, lp;
    scanf("%d%s", &lp, P+1);
    scanf("%d%s", &ls, S+1);
    return 0;
}

我们要将P在S内作为子串出现的开始下标输出。

我们可以思考一下,我们在求字串最长相同前后缀时,和我们在求P在S内作为子串出现也是同一个问题。(此时P与S作为同一个字符串看待)

现在问题就是如何快速的求出字串最长相同前后缀。

所以我们令ne[n]为P中以第n位为结尾的字串最长相同前后缀。(只用对P串求字串最长相同前后缀)

所以我们又有代码:

int ne[maxn];

接下来就是求ne的过程了。

我们先贴出代码:

(P与S均于下标为1开始)

    for (int i = 2, j = 0; i <= lp; ++i)
    {
        while (j && P[i] != P[j + 1])j = ne[j];
        if (P[i] == P[j + 1])++j;
        ne[i] = j;
    }

在这里我们先扔出关于字串最长相同前后缀的定义:

假如A[]:abababf
看它的整体,则其
全部前缀为:
a,ab,aba,abab,ababa,ababab,ababab
全部后缀为:
f,bf,abf,babf,ababf,bababf,bababf
其前后缀长度不能为原串长

因此我们就有一个很明显的事实"ne[1]=0"。(至于为什么从i=2的原因,咱还没有搞(

 

我们以动态规划的视角观察这个东西,考虑能不能用ne[i-1]推出ne[i]。

ne[i]代表了以第i个字符结尾的字串最长相同前后缀大小。

当取到i时,也说明了前i个字符的字串也匹配成功,因此ne[0,i]有解。

---------------------------------------------------------------------

For()

{

我们设立一个指针j,j指向与ne[i-1]匹配的左串末尾。

因此我们也确保了有P[0,j]==P[i-1-j,i-1]。

(1)当P[j+1]==P[i]时:

  有P[0,j+1]==P[i-j-1,i],也就是ne[i]=j+1;

  break;

(2)当P[j+1]!=P[i]时:

  也就没有P[0,j+1]==P[i-j-1],因此对于ne[i]的求解仍需要循环求解(此后j变为ne[ne[i-1]]匹配的左串末端),直至答案求出

(3)ne[i]=0;

}

---------------------------------------------------------------------

根据以上的思想,我们就可以得出以下代码:

#include<cstdio>
const int maxn = 1e5 + 10;
char S[maxn*10], P[maxn];
int ne[maxn];
int main()
{
    int ls, lp;
    scanf("%d%s", &lp, P+1);
    scanf("%d%s", &ls, S+1);
    for (int i = 2, j = 0; i <= lp; ++i)
    {
        while (j && P[i] != P[j + 1])j = ne[j];
        if (P[i] == P[j + 1])++j;
        ne[i] = j;
    }
    for (int i = 1, j = 0; i <= ls; ++i)
    {
        while (j && S[i] != P[j + 1])j = ne[j];
        if (S[i] == P[j + 1])++j;
        if (j == lp)
        {
            printf("%d ", i - lp);
            j = ne[j];
        }
    }
    return 0;
}

 

标签:831,int,ne,后缀,maxn,字串,KMP,字符串,AcWing
来源: https://www.cnblogs.com/Inabameguru/p/14932861.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有