KMP解决字符串最小循环节相关问题
经典问题 : 给出一个由某个循环节构成的字符串,要你找出最小的循环节,例如 abababab 最小循环节当是 ab ,而类似 abab 也可以成为它的循环节,但并非最短。
分析 :
对于上述问题有两个结论
如果对于next数组中的 i, 符合 i % ( i - next[i] ) == 0 && next[i] != 0 , 则说明字符串循环,而且
循环节长度为: i - next[i]
循环次数为: i / ( i - next[i] )
水平有限,用自己的语言描述怕有差错,给出一个参考博客 ==> http://www.cnblogs.com/jackge/archive/2013/01/05/2846006.html
再抛一个问题 : 有没有想过对于一个不完整的循环串要补充多少个才能使得其完整?
答案是==>(循环节长度) - len%(循环节长度) 即 (len - next[len]) - len%(len - next[len])
为什么? (以下胡扯,看不懂就掠过吧.........)
首先考虑整串就是循环节构成的情况,类似 abcxabcx 观察构造出来的next值显然满足上式,得出答案 0
那现在考虑不完整的情况,例如 abcabca 、其 next 值为 -1 0 0 0 1 2 3 4 。现在考虑末尾的 a,若没有它,而是将 c 作为末尾则会在 len 失配的时候会回溯道下一个循环节的末尾即 abca , 那现在多了一个a,那么回溯当然也应该是(循环节长度 + 1) 即 abcab,故 len 那里无论是否刚好为循环节的末尾,只是个"残"的末尾,未圆满的循环节,len-next[len]也是循环节长度,那需要补多少个呢?现在就很显然了!下面相关题目的 ① 就是这样的一个问题。
相关题目 :
题意 : 给出一个字符串,问你最少补充多少个字母才能使得字符串由两个或者以上的循环节构成
分析 : 由结论可知,如果字符串循环,那么最小循环节的长度为 len - next[len] ,并且这个字符串总长能被循环节长度整除说明字符串已经循环,否则 len % (len - next[len]) 则为多出来的部分,例如 abcabcab ==> len - next[len] = 3,而 len % 3 == 2 很明显就是余出来两个,这两个应当是循环节的头两个字母,对于其他串也可以自己模拟看看,所以需要补充的就是 循环节长度 - 多余出来的长度
#include<stdio.h> #include<string.h> using namespace std; ; char mo[maxn]; int Next[maxn], moL, nCase; inline void GetNext() { , j = -; Next[i] = j; while(i < moL){ && mo[i]!=mo[j]) j = Next[j]; Next[++i] = ++j; } } int ans() { GetNext(); ) return moL; int Period_len = moL - Next[moL]; int Remain = moL % Period_len; ) ; return Period_len - Remain; } int main(void) { scanf("%d", &nCase); while(nCase--){ scanf("%s", mo); moL = strlen(mo); printf("%d\n", ans()); } ; }
题意 : 给出一个字符串,叫你给出这个字符串存在的不同循环节长度以及个数 ( 循环节构成的不一定是整个字符串,也有可能是其子串 )
分析 : 根据以上的结论,我们只要让构造出字符串的next数组,而后一个for循环判断当前长度和当前最小循环节长度是否是倍数关系,即 i % ( i - next[i] ) == 0 && next[i] != 0,就能判断是否为一个循环节了,循环节的长度自然是 i / (i-next[i])
#include<stdio.h> using namespace std; ; char mo[maxn]; int Next[maxn], moL; inline void GetNext() { , j = -; Next[i] = j; while(i < moL){ && mo[j]!=mo[i] ) j = Next[j]; Next[++i] = ++j; } } inline void PrintAns() { GetNext(); int Period; ; i<=moL; i++){ ){ Period = i - Next[i]; ){ printf("%d %d\n", i, i/Period); } } }puts(""); } int main(void) { ; while(~scanf("%d", &moL) && moL){ scanf("%s", mo); printf("Test case #%d\n", Case++); PrintAns(); } ; }
③ HUST 1010 The Minimum Length
题意 : 假设 A 是一个循环字符串,现在截取 A 的某一段子串 B 出来,给出 B 问你构成 A 的循环节的最小长度是多少?
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; ; int Next[maxn], moL; char mo[maxn]; inline void GetNext() { , j = -; Next[i] = j; while(i < moL){ && mo[i]!=mo[j]) j = Next[j]; Next[++i] = ++j; } } int Ans() { GetNext(); ) return moL; else return moL - Next[moL]; } int main(void) { while(~scanf("%s", mo)){ moL = strlen(mo); printf("%d\n", Ans()); } ; }
题意 : 给你一个字符串,问你它由多少个相同的字符串拼接而成
分析 : 直接找算出最小循环节长度,如果字符循环,则答案为 len / (循环节长度) ,而对于 len % (循环节长度) != 0 和 next[len] == 0 的情况答案就是 1 了
#include<string.h> #include<stdio.h> using namespace std; ; int Next[maxn], moL; char mo[maxn]; inline void GetNext() { , j = -; Next[i] = j; while(i < moL){ && mo[i]!=mo[j]) j = Next[j]; Next[++i] = ++j; } } int Ans() { GetNext(); ) ; int Period = moL - Next[moL]; ) ; return moL / Period; } int main(void) { ]!='.'){ moL = strlen(mo); printf("%d\n", Ans()); } ; }
⑤ POJ 2752 Seek the Name, Seek the Fame
题意 : 给出一个字符串,问你所有关于这个字符串的前缀和后缀相同的长度,比如 abcab 有 1 "a"、2 "ab"、5 "abcab"
分析 : 这里就要巧妙利用到 next 数组的性质了,根据next数组定义可以知道 next[len] 表示一个从头开始长度为 next[len] 的前缀和相同长度的后缀相等,那么next[ next[len] ]呢?next[ next[ next[len] ] ]呢?这里的一层层嵌套实际上都是一个长度为 next[ next[len] ] 或者 长度 next[ next[ next[len] ] ]的前缀和后缀相等,自己构造个数组画画图也能得出来这个规律,那么到此,这个问题是不是被圆满的解决了呢!
#include<string.h> #include<stack> #include<stdio.h> using namespace std; ; char mo[maxn]; int Next[maxn], moL; inline void GetNext() { , j = -; Next[i] = j; while(i < moL){ && mo[j]!=mo[i]) j = Next[j]; Next[++i] = ++j; } } inline void PrintAns() { moL = strlen(mo); GetNext(); int tmp = Next[moL]; stack<int> ans;///根据题目要求需要递增输出长度,而我们得出的答案顺序正好相反,所以利用栈存储 ){///直到头为止 ans.push(tmp); tmp = Next[tmp]; } while(!ans.empty()){ int Top = ans.top(); ans.pop(); if(Top) printf("%d ", Top); } printf("%d\n", moL); } int main(void) { while(~scanf("%s", mo)){ PrintAns(); } ; }
KMP解决字符串最小循环节相关问题的更多相关文章
- hdu 4333"Revolving Digits"(KMP求字符串最小循环节+拓展KMP)
传送门 题意: 此题意很好理解,便不在此赘述: 题解: 解题思路:KMP求字符串最小循环节+拓展KMP ①首先,根据KMP求字符串最小循环节的算法求出字符串s的最小循环节的长度,记为 k: ②根据拓展 ...
- poj 2406 Power Strings【字符串+最小循环节的个数】
Po ...
- [POJ2406&POJ1961]用KMP解决字符串的循环问题两例
翻阅了一下网上资料,发现大部分都说这题是找规律...或是说YY出的一个算法..不会证明... 然后就脑补了一下证明 ~ 结论:对于一个字符串S[1..N],如果N mod (N-next[N])=0 ...
- KMP解决最小循环节问题
# 10035. 「一本通 2.1 练习 1」Power Strings [题目描述] 给定若干个长度 $\le 10^6$ 的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的.如 ...
- [KMP求最小循环节][HDU3746][Cyclic Nacklace]
题意 给你个字符串,问在字符串末尾还要添加几个字符,使得字符串循环2次以上. 解法 无论这个串是不是循环串 i-next[i] 都能求出它的最小循环节 代码: /* 思路:kmp+字符串的最小循环节问 ...
- KMP + 求最小循环节 --- POJ 2406 Power Strings
Power Strings Problem's Link: http://poj.org/problem?id=2406 Mean: 给你一个字符串,让你求这个字符串最多能够被表示成最小循环节重复多少 ...
- HDU 3746 (KMP求最小循环节) Cyclic Nacklace
题意: 给出一个字符串,要求在后面添加最少的字符是的新串是循环的,且至少有两个循环节.输出最少需要添加字符的个数. 分析: 假设所给字符串为p[0...l-1],其长度为l 有这样一个结论: 这个串的 ...
- [KMP求最小循环节][HDU1358][Period]
题意 求所有循环次数大于1的前缀 的最大循环次数和前缀位置 解法 直接用KMP求最小循环节 当满足i%(i-next[i])&&next[i]!=0 前缀循环次数大于1 最小循环节是i ...
- HDU 1358 Period(KMP+最小循环节)题解
思路: 这里只要注意一点,就是失配值和前后缀匹配值的区别,不懂的可以看看这里,这题因为对子串也要判定,所以用前后缀匹配值,其他的按照最小循环节做 代码: #include<iostream> ...
随机推荐
- AVR单片机教程——序言
我一直觉得现在的网络环境对电子技术的学习有一点问题,但始终无法确切地指出,更何况网络上相关资源已经那么丰富. 但我觉得是问题的,无论它到底是不是问题,对我来说总归是一个问题.我学习也不算深入,很多东西 ...
- 织梦安全防护:禁止uploads、data、templets执行脚本
下面介绍下如何针对uploads.data.templets做PHP脚本限制:对uploads.data.templets 三个目录做执行php脚本限制,就算被上传了木马文件到这些文件夹,也是无法运行 ...
- WebSocket 的应用
后面用到了再来做整理 链接地址:https://www.cnblogs.com/zhaof/p/9833614.html
- activemq BytesMessage || TextMessage
需求:使用 python 程序向 activemq 的主题推送数据,默认推送的数据类型是 BytesMessage,java 程序那边接收较为麻烦,改为推送 TextMessage 类型的数据 解决方 ...
- 测试人员必须掌握的linu常用命令
有些公司需要测试人员部署程序包,通过工具xshell. 现在我将总结下工作需要用到的最多的命令 ls 显示文件或目录 pwd ...
- VBA Exit For语句
当想要根据特定标准退出For循环时,就可以使用Exit For语句.当执行Exit For时,控件会立即跳转到For循环之后的下一个语句. 语法 以下是在VBA中Exit For语句的语法. Exit ...
- python使用Pyinstaller打包
一.前言 python文件打包,将.py文件转化成.exe文件(windows平台),可以使用Pyinstaller来打包 Pyinstaller可以在全平台下使用,但是请注意打包生成的文件不能在全平 ...
- synchronize与lock
1. synchronize的作用 synchronize是java最原始的同步关键字,通过对方法或者代码块进行加锁实现对临界区域的保护.线程每次进去同步方法或者代码块都需要申请锁,如果锁被占用则会等 ...
- AJAX中错误代码解释以及http中的错误代码解释
xmlhttp.readyState的值及含义: 0:请求未初始化(还没有调用 open()). 1:请求已经建立,但是还没有发送(还没有调用 send()). 2:请求已发送,正在处理中(通常现在可 ...
- c# VS.NET 中的调试工具