查看原题

题意大致是:给你一个字符串算这里面全部前缀出现的次数和。比方字符串abab,a出现2次。ab出现2次,aba出现1次。abab出现1次。总计6次。

而且结果太大。要求对1007进行模运算。

AC代码

#include <iostream>
using namespace std;
#include <string>
string s;
int n,Next[200005];
void getNext()
{
int len = n;
Next[0]=-1;
int i=0,j=-1;
while (i<len)
{
if(j==-1||s[i]==s[j])
{
++i;
++j;
Next[i]=j;
}
else
j = Next[j];
}
} void main()
{
int t;
cin>>t;
while (t--)
{
cin>>n;
cin>>s;
getNext();
int sum=0;
for(int i=1;i<=n;i++)
{
int j=i;
while(j)
{
sum = (sum+1)%10007;
j = Next[j];
}
}
cout<<sum<<endl;
}
}

KMP的next数组

概述

贴代码不是目的,解说算法才是关键。!

。解题的思路是使用了 KMP 算法,然而把并非完整的KMP算法。仅仅用到了它的next数组的求法。

然而这正是KMP算法本身的关键所在。关于上面代码中getNext函数中进行的求next数组的实现部分,属于经典实现。模板代码。

非常easy找到。这里关键在于解说next数组的思想。

在漫天飞的网络资料中,next数组的表示方法大致有两种:

  • next数组第一位为-1
  • next数组第一位为0

基本上是异曲同工。这里我用的是首元素为-1的解决方式,要注意的是若是首元素为-1的方案。那么next数组的大小是模式串长度+1!举个样例:

下标 0 1 2 3 4
模式串 a b a b  
next数组 -1 0 0 1 2

        当然了,这里我表示的是c++的string字符串。不是C风格字符串,所以没写'\0'.假设是C风格字符串(字符数组)那么红色部分就是'\0'了。只是这不是重点,不是么?

在KMP算法中,关于next数组一般也作两种理解(以next数组首元素为-1为例,为0时表述略有不同):

  1. 在模式串在某处与主串失配时,模式串应该回溯的位置。

  2. 以当前位置的前一位为结尾,其之前字符串与该串前缀相配的最大长度。

以下,略为解释一下这两点:

第一点

比方有一主串abacabab。有一模式串abab。要从主串之中查找是否包括模式串。那么我们依次遍历两个串,如果遍历两串有两个指针(逻辑意义上的指针)。或者称为光标。

開始时,前三位都能匹配。

下标 0 1 2 3 4 5 6 7
主串 a b a c a b a b
模式串 a b a b        

然后在下标为3处。也就是红色部分失配了。

那么朴素的字符串匹配算法就是要让主串的指针移动到下标为1.模式串指针归零,即移到首位。然而这非常明显是低效的操作。

KMP算法则是在这样的情况下。不改动主串的指针,仅仅改动模式串指针,故KMP算法又称无回溯KMP算法。那么模式串指针改动为什么呢,那就要看next数组了。

在上例中在下标为3处失配,则去看next[3],没错是 1 。

于是

下标 0 1 2 3 4 5 6 7
主串 a b a c a b a b
模式串     a b a b    

直接把模式串的指针移动到 下标为 1 处。再次失配,则观察 next[1] =0.继续反复上一过程。直至遍历完毕。KMP算法效率为O(m+n),当中m和n分别为主串和模式串的长度。

第二点

我们再次观察next数组的表格。

下标 0 1 2 3 4 5 6 7
主串 a b a c a b a b
模式串 a b a b        
  • 当下标为1时,要看它前一位的字符串,也就是看a,自身匹配不算。

    next数组为0。

  • 当下标为2时,要观察ab,a与b不匹配。next数组为0。
  • 当下标为3时,要观察aba,此时末尾的a与前缀a匹配,由于匹配长度为1所以next数组为1.
  • 当下标为4时。要观察abab,此时末尾的ab与前缀ab匹配,由于匹配长度为2所以next数组为2.

回到本题

代码中:

        int sum=0;
for(int i=1;i<=n;i++)
{
int j=i;
while(j)
{
sum = (sum+1)%10007;
j = Next[j];
}
}

用于求解全部前缀出现次数和。那么为什么这样呢?

首先看for循环,从1遍历到n,大家应该非常明确了。

我们的next数组的长度比串长度多1个。

while(j)造成的情况就是for循环中i = 1,2,3……n都会使sum+1.

这是非常好理解的由于,比方abab,那么 a。ab。aba,abab。这4个前缀肯定会算1个的对不?那么长度为n的字符串也会至少使sum+n对不。

然后接下来是 j = next[j].接下来我们用逆向思维来解说,另举一例。另有以字符串ababa,求它的sum(前缀出现次数和)。我们能够得到它的next数组:

下标 0 1 2 3 4 5
模式串 a b a b a  
next数组 -1 0 0 1 2 3

代入到上述代码中。和abab相比,仅仅多了一位。所以直接看 i 等于n(n为5)的时候。在sum=6(abab的sum值为6)的基础上来看。

  • j=i=5                //表示的是ababa这个长度为5的最长前缀
  • while(j)成立。sum=6+1=7
  • j=next[5]=3      //表示的是aba这个长度为3的前缀
  • while(j)成立,sum=7+1=8
  • j=next[3]=1      //表示的是a这个长度为1的最短前缀
  • while(j)成立。sum=8+1=9
  • j=next[1]=0.
  • while(j)不成立,结束。
  • 终于sum=9

要理解上面的凝视部分,须要再回到前面去看关于next数组解释的 第二点

hdu3336解读KMP算法的next数组的更多相关文章

  1. poj 2406:Power Strings(KMP算法,next[]数组的理解)

    Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 30069   Accepted: 12553 D ...

  2. KMP算法的next[]数组通俗解释

    原文:https://blog.csdn.net/yearn520/article/details/6729426 我们在一个母字符串中查找一个子字符串有很多方法.KMP是一种最常见的改进算法,它可以 ...

  3. hdu 1358:Period(KMP算法,next[]数组的使用)

    Period Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  4. KMP算法的Next数组详解

    转载请注明来源,并包含相关链接. 网上有很多讲解KMP算法的博客,我就不浪费时间再写一份了.直接推荐一个当初我入门时看的博客吧:http://www.cnblogs.com/yjiyjige/p/32 ...

  5. KMP算法的Next数组详解 转

    这个写的很好,还有讲kmp,值得一看. http://www.cnblogs.com/tangzhengyue/p/4315393.html 转载请注明来源,并包含相关链接. 网上有很多讲解KMP算法 ...

  6. 浅谈KMP算法及其next[]数组

    KMP算法是众多优秀的模式串匹配算法中较早诞生的一个,也是相对最为人所知的一个. 算法实现简单,运行效率高,时间复杂度为O(n+m)(n和m分别为目标串和模式串的长度) 当字符串长度和字符集大小的比值 ...

  7. KMP算法的Next数组详解(转)

    转载请注明来源,并包含相关链接. 网上有很多讲解KMP算法的博客,我就不浪费时间再写一份了.直接推荐一个当初我入门时看的博客吧: http://www.cnblogs.com/yjiyjige/p/3 ...

  8. KMP算法(next数组方法)

    KMP算法之前需要说一点串的问题: 串: 字符串:ASCII码为基本数据形成的一堆线性结构. 串是一个线性结构:它的存储形式: typedef struct STRING { CHARACTER *h ...

  9. KMP算法中next数组的理解与算法的实现(java语言)

    KMP 算法我们有写好的函数帮我们计算 Next 数组的值和 Nextval 数组的值,但是如果是考试,那就只能自己来手算这两个数组了,这里分享一下我的计算方法吧. 计算前缀 Next[i] 的值: ...

随机推荐

  1. linux题目整理(一)

    1.Linux如何挂载windows下的共享目录? mount.cifs /IP地址/server/ /mnt/server -O user=administrator password=yourpa ...

  2. 设计模式-python实现

    设计模式是什么? 设计模式是经过总结.优化的,对我们经常会碰到的一些编程问题的可重用解决方案.一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码.反之,设计模式更为高级,它是一种必须在特定情 ...

  3. hdu 5138(水题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5138 反着来. #include<iostream> #include<cstdi ...

  4. HDU 6301.Distinct Values-贪心、构造字典序最小的数列 (2018 Multi-University Training Contest 1 1004)

    HDU6301.Distinct Values 这个题就是给你区间要求区间内的数都不相同,然后要求是字典序最小,直接贪心走一遍,但是自己写的时候,思路没有错,初始化写挫了... 将区间按左端点小的排序 ...

  5. 牛客小白月赛3 B 躲藏【动态规划/字符串出现cwbc子序列多少次】

    链接:https://www.nowcoder.com/acm/contest/87/B来源:牛客网 XHRlyb和她的小伙伴Cwbc在玩捉迷藏游戏 Cwbc藏在多个不区分大小写的字符串中. 好奇的X ...

  6. 洛谷——P1258 小车问题

    P1258 小车问题 题目描述 甲.乙两人同时从A地出发要尽快同时赶到B地.出发时A地有一辆小车,可是这辆小车除了驾驶员外只能带一人.已知甲.乙两人的步行速度一样,且小于车的速度.问:怎样利用小车才能 ...

  7. HDU 5916: Harmonic Value Description

    题目描述 The harmonic value of the permutation $p_1,p_2,\cdots p_n$ is$$\sum_{i=1}^{n-1} gcd(p_i.p_{i+1} ...

  8. 洛谷 P3804 后缀自动机

    题目描述 给定一个只包含小写字母的字符串SS , 请你求出 SS 的所有出现次数不为 11 的子串的出现次数乘上该子串长度的最大值. 输入输出格式 输入格式: 一行一个仅包含小写字母的字符串SS 输出 ...

  9. Uva 11542 Square

    题目中说数组中的数的最大质因子不超过500,我们筛出≤500的质数,然后考虑对每个质数列一个方程组.. 然后这几乎就是高斯消元求解异或方程组的模板题了.... 注意答案是 2^(自由元数量)-1,因为 ...

  10. windows下如何添加、删除和修改静态路由

    1.添加一条路由表 route add 192.168.100.0 mask 255.255.255.248 192.168.1.1 metric 3 if 2 1 2 添加一条路由记录,所有到192 ...