天天看点

KMP专题【完结】

第一题 hdu 1711 Number Sequence

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=1711">点击打开hdu 1711</a>

思路:

1 kmp是用来匹配字符串,只能够匹配单一的字符串

2 kmp的算法的过程:

  1:假设文本串的长度为n,模式串的长度为m;

  2:先例用O(m)的时间去预处理next数组,next数组的意思指的是当前的字符串匹配失败后要转到的下一个状态;

  3:利用o(n)的时间去完成匹配;

3 时间复杂度为o(n+m)即o(n);

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8119895">点击查看代码</a>

第二题 hdu 1686 oulipo

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=1686">点击打开hdu 1686</a>

1 题目要求的是给定一个模式串个一个文本串,求出模式串在文本串中出现几次

2 典型的KMP问题,只要套上模板即可。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8119971">点击查看代码</a>

第三题 hdu 2087 剪花布条

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=2087">点击打开hdu 2087</a>

1 题目要求的是给定一个文本串和给定一个模式串,求文本串中有几个模式串。

2 注意文本串为"aaaaaa",模式串"aa"的时候,ans = 3 而不是5。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8120037">点击查看代码</a>

第四题 hdu 3746 Cyclic Nacklace

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=3746">点击打开hdu 3746</a>

1 题目要求的是给定一个字符串,问我们还需要添加几个字符可以构成一个由n个循环节组成的字符串。

2 可知我们应该先求出字符串的最小循环节的长度:假设字符串的长度为len,那么最小的循环节就是cir = len-next[len] ; 如果有len%cir == 0,那么这个字符串就是已经是完美的字符串,不用添加任何字符;如果不是完美的那么需要添加的字符数就是cir - (len-(len/cir)*cir)),相当与需要在最后一个循环节上面添加几个。

3 如果cir = 1,说明字符串只有一种字符例如“aaa” ; 如果cir = m说明最小的循环节长度为m,那么至少还需m个;如果m%cir == 0,说明已经不用添加了

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8120977">点击查看代码</a>

第五题 hdu 1358 Period

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=1358">点击打开hdu 1358</a>

1 题目要求的是给定一个长度为n的字符串,求出字符串的所有前缀字符串中该字符串刚好由k个最小循环节够成,由于题目要求k最大那么就是这个循环节最小

2 只要先求出next数组,然后去枚举所有的前缀找到满足的输出长度和k

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8121127">点击查看代码</a>

第六题 hdu 2203 亲和串

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=2203">点击打开hdu 2203</a>

1 题目要求的是给定字符串s1 和 s2,问s1能否通过移位得到使得s2包含在s1里面。

2 很显然的kmp的模板题,只须在s1后面在添上一个s1即可。这里特别注意strcat的使用

3 strcat函数,函数的原行strcat(char *s , char *p);注意这里的s和p所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串;所以假设s = “abc”,现在想得到“abcabc”那么不能直接的strcat(s , s),而是先用一个tmp数组存储s,即strcpy(tmp , s , sizeof(s)) , 然后在strcat(s , tmp);

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8121707">点击查看代码</a>

第七题 hust 1010 The Minimum Length

<a target="_blank" href="http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10369">点击打开hust 1010</a>

1 题目要求的是,有一个字串A,现在利用A组成了一个新的字符串AAAAA...,现在从这个新的字符串的两个不同位置剪下去得到字符串B,问A的最小长度

2 由于B里面的字符都是来自A,那么如果要A最小那么最小值就是等于B的最小循环节。

3 直接对B求最小循环节

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8121908">点击查看代码</a>

第八题 poj 2406 Power Strings

<a target="_blank" href="http://poj.org/problem?id=2406">点击打开poj 2406</a>

1 题目要求的是给定一个字符串找到最小循环节的个数,但是这里有个限制的地方就是如果这个字符串不是刚好由n个最小循环节组成那么就认为一整串才是一个循环节

2 题目说了输入的字符是可打印的,所以应该用gets读入,判断终止的时候用strcmp。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8122167">点击查看代码</a>

第九题 poj 2752 Seek the Name, Seek the Fame

<a target="_blank" href="http://poj.org/problem?id=2752">点击打开poj 2752</a>

1 题意要求的找出满足既是字符串的s的前缀又是后缀的字串输出该字串的长度。

2 先看看next数组的含义:

   1:next数组只和模式串本身有关和文本串是无关的,因为next表示的是当匹配失败后模式串要回溯到哪个位置。

   2:next数组存储的数据是用来当模式串与主串不匹配的时候要模式串回退到第几个字符与主串再重新匹配,我们知道KMP算法的主串是不回朔的,当不匹配的时候我们不是退回到开始位置重新匹配,而是利用已经匹配的结果将模式串回朔到下一个位置,这个位置比开始位置更近一步;

简单的说就是next[ j ]的值保存的是当模式串中第 j 个字符与主串第 i 个字符不匹配时候,模式串中的哪个字符 重新与主串第 i 个再匹配,这样总的字符比较次数比从开始位置比较的次数就少了。

   3:next[j]存储的就是模式串前j个字符里前缀和后缀最大的匹配长度;也就是有j = next[j] ; 假设有模式串“abcabx”,那么next[5] = 2就是前5个字符里前缀和后缀匹配最长的长度为2即“ab”;那么就是说如果next[len] = ans , 整个串的前缀和后缀最长匹配的长度就是ans,上面的字符串“abcabx”的最长匹配就是0。

   4:在模式串与标准串进行匹配时,指向他们的指针分别为j、i;当p[j]!=s[i]时,j直接变为next[j],新的p[j]继续与s[i]比较,如果不相等继续进行此操作……那么数组next[j]同样反映了,在模式串p的第j个位置之前,p[0]~p[next[j]-1]与p[i-next[j]]~p[i-1]这两段是完全一样的。假设模式串为“abcdabx”,手动模拟即可知道。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8125573">点击查看代码</a>

第十题 poj 3080 Blue Jeans

<a target="_blank" href="http://poj.org/problem?id=3080">点击打开poj 3080</a>

1 题目要求的是给定m个DNA序列,每个DNA序列长度固定为60,问m个DNA序列的最长的公共子串

2 初看题目无从下手,但是你仔细研究发现是要找m个序列的公共子串,那么这个子串必定存在于第一个DNA序列里面。这个时候就可以想到去枚举第一个DNA序列的所有子串,由于长度为60那么最多3600个子串,由于m最多10个;所以算一下复杂度就是0(3600*n*m),n是60和m最大10,那么这样的复杂度是可以接受的。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8125840">点击查看代码</a>

第十一题 hdu 2594 Simpsons’ Hidden Talents

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=2594">点击打开hdu 2594</a>

1 题目要求的是给定两个字符串s1 , s2找到s1的最长前缀等于s2的后缀

2 很明显就是next数组的应用,我们知道next[j] = len,表示的前j个字符里面前缀和后缀的最长匹配长度为len。那么我们只要合并两个字符串然后求next数组即可。

3 注意以下的数据

abcabcabcabc

abcabcabcabcabc

输出 12

abcabc

abc

输出 3

我们知道如果合并了s1和s2的话,那么求出来的最长的长度是24 和 6显然是不行的,因为我们忽略了一个地方就是求出的最长的前缀的长度是不能超过

s1和s2的长度的,所以求出最长前缀长度后应该进行讨论。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8126286">点击查看代码</a>

第十二题 hdu 3336 Count the string

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=3336">点击打开hdu 3333</a>

1 题目要求的是给定一个字符串s,求字符串s的所有的前缀在s的匹配的次数之和mod10007.

2 很明显n&lt;= 200000,分析一下那么就要n个前缀如果每一个前最都去匹配s的话复杂度就是o(n^2),那么肯定是TLE的,所以要考虑另外的思路

3 我们知道next[j] = len,表示的是在前j个字符里前缀和后缀的最大的匹配的长度为len,所以根据next数组的性质,我们只要去枚举j的值从n-&gt;1,为什么要从n开始而不是1开始呢,这里因为是要求前缀的匹配数而不是后缀;

4 求sum的时候注意每一步都有可能超过范围,所以就要求一次sum同时取模一次。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8130830">点击查看代码</a>

第十三题 hdu 4300 Clairewd’s message

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=4300">点击打开hdu 4300</a>

1 题目要求的是给定一个不完整的由n个字符构成的字符串并且字符串有密文和明文两部分组成,现在要求完整的字符串。

2 很明显密文的长度不确定,现在又要求最短的字符串长度。由于在完整的字符串中密文和明文的长度是一样的,那么输入的字符串中至少有(n+1)/2是密文,所以我们假设密文后面的都是明文,那么我们将这些明文转化为密文后求next数组就可以知道前缀和后缀的最大的匹配数,那么如果匹配数越大就说明总的串的长度就越小。

3 但是有个地方需要注意,输入的字符串长度为n,那么至少(n+1)/2为密文,那么明文最多为tmp = n-(n+1)/2,所以next[n]的最大值是不能超过tmp的,如果超过了那么就另next[len] = tmp即可,说明已经最大了

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8134728">点击查看代码</a>

第十四题 hdu 1238 Substrings

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=1238">点击打开hdu 1238</a>

1 题目要求找到一个子串x,满足x或x的逆串是输入的n个字符串的子串,求最大的x,输出x的长度

2 题目的n最大100,每一个字符串的最大长度为100,那么暴力枚举子串就是o(n^2)才10000肯定是不会超时的,但是由于这里涉及到了逆串的问题,所以我们应该还要求出n个子串的逆串,然后在求最大的x。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8135788">点击查看代码</a>

第十五题 hdu 2328 Corporate Identity

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=2328">点击打开hdu 2328</a>

1 题意要求最长的公共子串,由于每一串的长度最长不超过200,所以可以选择暴力枚举最短的单词的子串来求出ans

2 利用kmp来匹配

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8139082">点击查看代码</a>

第十六题 hdu 3374 String Problem

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=3374">点击打开hdu 3374</a>

1 题目要求给定一个字符串求出最小和最大表示的rank和出现的times。

2 如果直接暴力枚举n 最大10^6肯定TLE,所以这了应该要用到的是求解一个字符串的最小和最大表示,然后利用kmp去匹配查找出现的次数

3 在利用kmp匹配的时候应该要注意不能多算,比如有abcder,那么用abcder去匹配abcderabcder的时候就有两次的匹配结果,但实际上这里只有一个,所以这个地方要注意。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8150135">点击查看代码</a>

第十七题 hdu 2609 How many

<a target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=2609">点击打开hdu 2609</a>

1 题目要求的是给定n个字符串,找出不同的字符串的个数。由于题目说了,字符串可以进行变换,也就是如果两个字符串相同那么它们的最小表示是相同的。

2 只要求出所有字符串的最小表示,然后利用set存储,最后set的元素个数就是最后的ans

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8150204">点击查看代码</a>

第十八题 fzu 1901 Period II

<a target="_blank" href="http://acm.fzu.edu.cn/problem.php?pid=1901">点击打开fzu 1901</a>

1 题目要求的找到所有满足S[i]=S[i+P] for i in [0..SIZE(S)-p-1]的前缀,并且长度为p。利用上面的式子可以等价的得到等式s[0,len-p-1] = s[p , len-1].

2 给个next数组的性质

   假设现在有一个字符串为ababxxxxabab。那么求出的next数组为00012001234,那么前缀和后缀最长的匹配数是4,然后下一个前缀和后缀匹配长度为next[4] = 2 , 然后下一个为next[2] = 0。

   所以有一个结论就是,假设当前求出的字符串的前缀和后缀的最长的匹配的长度为len,那么下一个满足的前缀和后缀互相匹配的长度为next[len]...依次

3 观察一下上面的等式,我们发现并不是我们所熟悉的前缀和后缀匹配的等价式。那么我们现在来看这个样列

            f z u f z u f z u f   长度为10

next    000 01 2 3 456 7

那么根据next数组就得到前缀和后缀的匹配长度依次为 7 4 1 0 ,那么这时候看看题目的p的可能长度为 3 6 9 10,那么有没有发现规律。

<a target="_blank" href="http://blog.csdn.net/chenguolinblog/article/details/8210244">点击查看代码</a>