ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【模版】字符串匹配 KMP 算法

2020-02-21 14:43:30  阅读:294  来源: 互联网

标签:nxt 匹配 int 模版 模式 算法 KMP include 失配



字符串匹配KMP算法


给出两个字符串 S1S_1S1​ 和 S2S_2S2​ ,其中 S2S_2S2​ 为 S1S_1S1​ 的子串.
1.1.1. 求出 S2S_2S2​ 在 S1S_1S1​中所有出现的位置.
2.2.2. 输出子串的前缀数组 nxt[i]nxt[i]nxt[i].


先引入两个概念(通俗解释):
模式串:要查找的字符串。(即 S2S_2S2​ )
文本串:被用来查找模式串的字符串。 (即 S1S_1S1​ )

将模式串与文本串做匹配时,若用传统的从头到尾匹配法,复杂度 O(N+M)O(N+M)O(N+M) 到 O(NM)O(N*M)O(N∗M) 不等。考虑用奇怪的玄学方法优化。
如果 模式串匹配到最后几位了,发现出现了失配,那么全面放弃还是挺可惜的,毕竟前边匹配了那么多。如果当前的模式串前面出现了 一个真子集,与该模式串前缀相同,那么该前缀可以向前移动过来啊,这一部分也一定匹配的。也就是说,将模式串整体向前移动也若干位,因为我们通过前缀移动自动匹配的,我们保证其匹配。
比如:
模式串: ABCABCDABCABCDABCABCD
文本串: ABCABCABCDABCABCABCDABCABCABCD
匹配前六个字符时成功,但是第七位不成功,但发现第 111、222、333 位字符与第 444、555、666 位字符相同,那么我们可以把前三位字符向前推进三位,然后再往后推进。这样就得到了优化。问题在于,当第七位失配时,如何确定第六位应该对应前边第几位呢,从这个样例来看,显然是第三位,所以引入 nxt[i]nxt[i]nxt[i] 数组,表示 在模式串第在模式串第 iii 位失配时位失配时,退应该退回到应该退回到 nxt[i]nxt[i]nxt[i] 位,再次向后匹配。所以我们应该预处理 nxt[i]nxt[i]nxt[i] 数组。
所以上边样例的 nxt[i]nxt[i]nxt[i] 的值(从下标 111 开始): 00012300、0、0、1、2、3、00、0、0、1、2、3、0
预处理方法如图所示:

int p = 0;
for(int i = 2; i <= len2; i++)
{
    while(p && s2[i] != s2[p+1])    p = nxt[p];
    if(s2[p+1] == s2[i])    p++;
    nxt[i] = p;
}

那么与文本串匹配时的书写,如下所示:

p = 0;
for(int i = 1; i <= len1; i++)
{
    while(p && s2[p+1] != s1[i])  p = nxt[p];
    if(s2[p+1] == s1[i])    p++;
    if(p == len2)
    {
        printf("%d\n",i-len2+1);
        p = nxt[p];
    }
}

还没做练习题,待学完AC自动机后再补题补坑吧(2020年2月21日 14:12:40)

完整代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std;
char s1[1001000],s2[1000100];
int nxt[1001000];
int main()
{
    scanf("%s%s",s1+1,s2+1);
    int len1 = strlen(s1+1), len2 = strlen(s2+1);
    int p = 0;
    for(int i = 2; i <= len2; i++)
    {
        while(p && s2[i] != s2[p+1])    p = nxt[p];
        if(s2[p+1] == s2[i])    p++;
        nxt[i] = p;
    }
    p = 0;
    for(int i = 1; i <= len1; i++)
    {
        while(p && s2[p+1] != s1[i])  p = nxt[p];
        if(s2[p+1] == s1[i])    p++;
        if(p == len2)
        {
            printf("%d\n",i-len2+1);
            p = nxt[p];
        }
    }
    for(int i = 1; i <= len2; i++)
        printf("%d ",nxt[i]);
    system("pause");
    return 0;
}

例题:[模版]KMP算法

oier991215 发布了12 篇原创文章 · 获赞 12 · 访问量 1198 私信 关注

标签:nxt,匹配,int,模版,模式,算法,KMP,include,失配
来源: https://blog.csdn.net/LH_991215/article/details/104425908

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

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

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

ICode9版权所有