hdu3336解读KMP算法的next数组
2017-05-03 13:41
204 查看
查看原题
题意大致是:给你一个字符串算这里面全部前缀出现的次数和。比方字符串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 |
在KMP算法中,关于next数组一般也作两种理解(以next数组首元素为-1为例,为0时表述略有不同):
在模式串在某处与主串失配时,模式串应该回溯的位置。
以当前位置的前一位为结尾,其之前字符串与该串前缀相配的最大长度。
以下,略为解释一下这两点:
第一点
比方有一主串abacabab。有一模式串abab。要从主串之中查找是否包括模式串。那么我们依次遍历两个串,如果遍历两串有两个指针(逻辑意义上的指针)。或者称为光标。開始时,前三位都能匹配。
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
主串 | a | b | a | c | a | b | a | b |
模式串 | a | b | a | b |
那么朴素的字符串匹配算法就是要让主串的指针移动到下标为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 |
第二点
我们再次观察next数组的表格。下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
主串 | a | b | a | c | a | b | a | b |
模式串 | a | b | a | b |
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 |
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数组
- KMP算法Next数组的应用
- KMP算法中怎么求next数组
- POJ 2406 KMP算法next数组理解
- 字符串匹配KMP算法中Next[]数组和Nextval[]数组求法
- KMP算法求next数组和nextval数组
- KMP算法---核心就是NEXT数组求解---最长真后缀与前缀相同的字符数
- #1015 : KMP算法(kmp裸题,把next数组定义成了char类型,wa了半天 )
- 详解KMP算法中Next数组的求法
- KMP算法中的两种next数组:next和nextval
- KMP算法NEXT数组计算方法
- KMP算法next数组计算--字符串方式
- 【KMP】多种KMP算法next数组的求解
- 转载大神的~~~~~~ KMP算法的前缀next数组最通俗的解释,如果看不懂我也没辙了
- KMP算法求next数组和nextval数组
- KMP算法中next数组和nextval数组值的推导
- KMP算法之next数组分析
- KMP算法和KMP算法中next数组的讲解
- KMP算法的前缀next数组最通俗的解释,如果看不懂我也没辙了
- POJ 1961 Period KMP算法next数组的应用