zoukankan      html  css  js  c++  java
  • luogu3375 【模板】KMP字符串匹配

    题目大意:给出两个字符串s和p,其中p为s的子串,求出p在s中所有出现的位置。

    p[0, i-1]中,若存在最长的相等的后缀与前缀,则next[i]为那个前缀的末尾位置的下一个位置。匹配时,如果p[i]!=s[j],因为p[0,i-1]中的后缀已经匹配成功,则把与其相等的前缀放在那个后缀的位置,也会匹配成功。所以让i=next[i]继续匹配即可。

    求next数组,要用递推。每次while循环体内解决的问题是:已知next[j]==k,求next[j+1]。如果p[j]==p[k],对于j+1来说,前缀的长度和后缀的长度都加1,还相等,把next[j+1]设成k+1即可;否则,令k=next[k],根据定义,p[0,next[k]-1]该前缀1能在p[0,k-1]中找到与其相等的后缀2,该p[0,k-1]整体该前缀3会在p[0,j-1]中找到与其相等的后缀4。因为1=2,2是3后缀,3=4,故1与4的后缀相等。就这样不断循环即可。

    #include <cstdio>
    #include <cstring>
    #include <cassert>
    using namespace std;
    
    const int MAX_STR = 1000010;
    
    void SetNext(char *p, int *next)
    {
        int len = strlen(p);
        int j = 0, k = -1;
        next[0] = -1;
        while (j < len)
        {
            if (k == -1 || p[j] == p[k])
            {
                /*if (p[j + 1] == p[k + 1])
                    next[++j] = next[++k];
                else*/
                    next[++j] = ++k;
            }
            else
                k = next[k];
        }
    }
    
    void GetP(char *s, char *p, int *next, int *ans)
    {
        int sLen = strlen(s), pLen = strlen(p), sPos = 0, pPos = 0, ansCnt = 0;
        while (sPos < sLen)
        {
            if (pPos == -1 || s[sPos] == p[pPos])
            {
                sPos++;
                pPos++;
            }
            else
                pPos = next[pPos];
            if (pPos == pLen)
            {
                ans[ansCnt++] = sPos - pPos + 1;
                pPos = 0;
                sPos = sPos - pLen + 2;
            }
        }
    }
    
    int main()
    {
    #ifdef _DEBUG
        freopen("c:\noi\source\input.txt", "r", stdin);
    #endif
        static char s[MAX_STR], p[MAX_STR];
        static int next[MAX_STR], ans[MAX_STR], pLen;
        scanf("%s%s", s, p);
        pLen = strlen(p);
        SetNext(p, next);
        GetP(s, p, next, ans);
        for (int i = 0; ans[i]; i++)
            printf("%d
    ", ans[i]);
        for (int i = 1; i < pLen + 1; i++)
            printf("%d ", next[i]);
        printf("
    ");
        return 0;
    }
    View Code

    注意:

    • 是k==-1(pPos==-1),而不是next[k]==-1(next[pPos]==-1)。
    • 设置next时,k初值为-1,而不是0(看next的定义)。

    优化:若p[next[j]]==p[j],则实际匹配时,我们还要求next[next[j]]。因此,把代码中注释部分加上即可。

  • 相关阅读:
    C#使用WINDOW
    赵四小姐从十六岁开始跟张学良。跟一年,属奸情;跟三年,算偷情;跟六十年,便成为千古爱情!
    Microsoft Visual Studio 2010(VS2010)正式版 CDKEY / SN:
    C#中byte[]与string的转换
    sqlserver waitfor time '10:00' waitfor delay '1:00' 时间延时 和 间隔
    免费下载 精英讲解
    在决定使用ClickOnce发布你的软件前,应该知道的一些事情
    Windows7下注册OCX的注意事项
    用命令行以最快速简单的方式搭建MySQL数据库
    设计模式探索系列之Bridge模式
  • 原文地址:https://www.cnblogs.com/headboy2002/p/8453645.html
Copyright © 2011-2022 走看看