18940 最小循环节(KMP算法)
时间限制:1000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC;JAVA;PYTHON
Description
给定一个字符串,请计算这个字符串最多是由多少个相同的子字符串重复连接而成的。 如:acacac 最多有 3 个 ac 连接而成,bbbb最多由4个b连接而成,abc最多由1个abc连接而成。
此问题需求出整个字符串的最大相同真前后缀,需使用kmp算法或字符串哈希法,具体解释可看下图或百度最小循环节。
输入格式
一个字符串,长度不超过100000。
输出格式
组成字符串的最多重复连接子串的个数。
输入样例
ababab
输出样例
3
按照之前使用的next值计算技巧可知(之前的那篇计算的next值输出时,题目要求是错位输出):
计算的是最长前后缀相同的长度
ababab的为:001234
再看几个例子:
字符串 | pi数组 | len | 周期 p = n - len | 可重复次数 |
---|---|---|---|---|
ababab | 0 0 1 2 3 4 | 4 | 6 - 4 = 2 | 3 |
bbbb | 0 1 2 3 | 3 | 4 - 3 = 1 | 4 |
abcabcab | 0 0 0 1 2 3 4 | 4 | 8 - 4 = 4 | 2 |
abcde | 0 0 0 0 0 | 0 | 5 - 0 = 5 | 1 |
我们来看一下:
s = a b a b a b
↑
这个位置是 len = 4,也就是 abab
s 的结构是:
头部:a b a b
尾部: a b a b
你发现了吗?
-
这说明这个字符串前面一部分和后面一部分是重复的
-
所以它的结构很可能是某个短的字符串反复重复而成
第三步:周期的真正含义
我们现在来观察一个假设:
设字符串有周期 p
,如果:
s[0] == s[p]
s[1] == s[p+1]
s[2] == s[p+2]
...
这样不断循环重复,直到构成整个字符串 ⇒ 就叫它是一个周期。
在 ababab
中,我们尝试看看周期长度为 2
是否成立?
周期单位: ab 重复 3 次: ab ab ab
恰好等于字符串 ⇒ 周期成立!
第四步:为什么周期 = n - len?
我们知道:
-
最长相同的前后缀长度是
len
-
如果你把这部分“挖掉”,只剩中间的那个基本单元
-
也就是说周期 = 整个长度 - 匹配的前后缀长度 ⇒
周期 = n - len
在 ababab
中:
n = 6
len = 4
周期 p = 6 - 4 = 2
s[0..1] = ab,就是周期单元
ababab = ab + ab + ab
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
int n = s.size();
vector<int> pi(n);
// 构造前缀函数(KMP的next数组)
for (int i = 1; i < n; i++) {
int j = pi[i - 1];
while (j > 0 && s[i] != s[j]) {
j = pi[j - 1];
}
if (s[i] == s[j]) {
j++;
}
pi[i] = j;
}
// 获取最后一个位置的pi值
int len = pi[n - 1];
int period = n - len;
// 判断是否可以整除
if (n % period == 0) {
cout << n / period << endl;
} else {
cout << 1 << endl; // 不能整除则只能重复1次
}
return 0;
}