zoukankan      html  css  js  c++  java
  • HDU 6153 KMP 模式串后缀在目标串中的出现次数

    HDU6153:http://acm.hdu.edu.cn/showproblem.php?pid=6153

    Orz 果然字符串很神奇……(神奇到人哭出来啊TAT)果然算法理解的不够透彻的话,是无法灵活运用的QAQ

    其实只要简单的改一点点KMP的地方……

    KMP的next[i]存储的是模式串下标0至i处相同的前缀和后缀的最长长度,每次与目标串匹配的时候,会略过前后缀相同的部分以减少回溯,提高效率。

    由于每次匹配都是从前向后匹配的,因此对于模式串每次的匹配子串都是[0……i],是前缀,但是根据题目的要求,我们要找的是s2的子串[i……n],是后缀。

    其实只要把模式串reverse一下,就可以把后缀转化为前缀,然后在进行处理就方便了。

    对kmp理解的比较透彻的就不要听我瞎扯了……写的比较……emmmmm……不过还是很欢迎给窝这个连门槛都摸不到的小白提提建议的(^∇^*)

    可以用一个ll数组记录长度为i的前缀(也就是转化前的后缀)出现的次数(这里数组用crt表示)。(用ll……不要用int……会TLE)

    因为next数组本身记录的就是相同子串的长度,因此可以在每个循环内部对匹配过的字符的下标进行计数

    先码个代码:

    while (i < len1)
        {
            if(j==-1||s1[i]==s2[j])
              {  i++; j++;   }
            else j = nextt[j];
            num[j]++;
            if (j == len2) j = nextt[j];
        }

    下面拿题目的例子来解释一下出现次数的计数:

                 b     a    b    a    b    a    b    a

    next      -1    0    0    1    0    0    0    0

                a                                                        ——模式串目标串匹配过程

    crt        0     0    0     0       匹配失败,j=next[j]=-1;这里crt数组不更新

    crt        1     0    0     0

                       a

    crt       1      1    0     0

                       a    b

    crt       1      1     1                                         

                      a    b     a                  ——j==s2长度,但由于我们要在整个目标串中匹配,这里不能跳出,要继续匹配

    crt       1     1    1     1                                      因此又加了  if(j==len2)  j=next[j];

                                   a    b

    crt       1     1     2    1

                                   a    b    a

    crt       1     1     2    2

                  …………

                                               a   b    a

    crt      1     1    3    3

    可以发现,把crt计数放在每次j处理过之后,下标刚好就为目前子串的长度,所以就可以安心的记录啦;

    前面有提到,kmp的算法为了减少回溯,省略了相同部分的匹配,因此我们每次记录的只是当前相同前缀长度的个数,从上面的例子不难发现,

    除了第一次‘a'以外的其他的'a'的匹配都被省略了,其他都是从’ab'开始匹配的,每次匹配失败再次匹配时,省略了next[i]之前部分的计数,因此还需要进一步对计数数组进行处理。

    for (int i = len2; i >0; i--)                
           crt[nextt[i]] += crt[i];

    既然少了加回来就好了,匹配失败以后再次匹配时,都是从next[i]开始匹配的,因此,crt[next[i]]未计数的部分=crt[i],循环把len~1的部分加回来就OK了

    (记得是从len倒着往前加)

    下面看完整的代码。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int MAX = 1e6;
    const int mod = 1e9 + 7;
    int nextt[MAX + 10];
    char s1[MAX + 10];
    char s2[MAX + 10];
    long long num[MAX + 10];
    int t,len1,len2;
    void getnext()
    {
        int p=0, k = -1;
        nextt[0] = -1;
        while (p < len2)
        {
            if (k == -1 || s2[p] == s2[k])
            {    
                        p++;k++;
                         nextt[p] =k;
                    }
            else k = nextt[k];
        }
    }
    void kmp()
    {
        getnext();
        int i = 0, j = 0;
        while (i < len1)
        {
            if(j==-1||s1[i]==s2[j])
            {i++; j++;}
            else j = nextt[j];
            num[j]++;
            if (j == len2) j = nextt[j];
        }
    }
    int main()
    {
        cin >> t;
        while (t--)
        {
            memset(num,0, sizeof(num));
            cin >> s1;
            cin >> s2;
            len1 = strlen(s1);
            len2 = strlen(s2);
            reverse(s1, s1 + len1);
            reverse(s2, s2 + len2);
            kmp();
            long long ans = 0;
            for (int i = len2; i > 0; i--)
            {                
                num[nextt[i]] += num[i];
                ans = (ans + i*num[i]) % mod;
            }
                printf("%d
    ", ans);
        }
        return 0;
    }

    有什么不对的地方或者解释的不好的地方还请大家指出来( ̄▽ ̄)"

  • 相关阅读:
    Error creating bean with name 'eurekaAutoServiceRegistration'
    CentOS 下 安装 nginx 执行配置命令 ./configure 报错
    linux解压war包的命令
    idea中如何将一个普通项目转换为maven项目(或者导入Maven项目后没反应)
    IDEA报 : Lombok Requires Annotation Processing
    IDEA中如何添加RunDashboard
    @Controller 和 @RestController 的区别
    @RequestMapping 和 @GetMapping @PostMapping 区别
    批量提取指定文件夹下的所有文件名称及其路径
    TortoiseSVN的bin目录下面没有svn.exe
  • 原文地址:https://www.cnblogs.com/Egoist-/p/7435573.html
Copyright © 2011-2022 走看看