1. 题目背景与核心问题解析
"Power Strings"是《信息学奥赛一本通》第1457题,属于字符串匹配与周期性问题中的经典题型。这道题在NOIP/NOI等竞赛中多次出现变种,考察选手对KMP算法及其next数组特性的深入理解。
题目通常给出一个字符串S,要求找出其最大重复次数k,使得S能被表示为某个子串重复k次连接而成。例如:
- 输入"ababab",输出3(由"ab"重复3次构成)
- 输入"aaaa",输出4(由"a"重复4次构成)
- 输入"abac",输出1(无法表示为子串重复)
关键洞察:这类问题与常规字符串匹配的区别在于,它需要发现字符串自身的周期性结构,而非两个字符串间的匹配关系。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. KMP算法与next数组的妙用
2.1 标准KMP算法回顾
KMP算法的核心是通过预处理模式串得到next数组,其中next[i]表示模式串前i个字符组成的子串中,最长相等前后缀的长度。传统应用场景是加速文本匹配过程。
cpp复制void getNext(const string &p, vector<int> &next) {
next[0] = -1;
int i = 0, j = -1;
while (i < p.length()) {
if (j == -1 || p[i] == p[j]) {
++i; ++j;
next[i] = j;
} else {
j = next[j];
}
}
}
2.2 next数组的周期性特征
对于Power Strings问题,关键在于发现:当字符串具有周期性时,next数组会呈现特定规律。设字符串长度为n,若n % (n - next[n]) == 0,则字符串由前n-next[n]个字符重复构成。
证明思路:
- 令L = n - next[n],即最小周期长度
- 若n能被L整除,则整个字符串可被均分为n/L个完整周期
- 否则字符串末尾存在不完整周期,此时k=1
3. 完整解题代码实现
3.1 C++标准解法
cpp复制#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
string s;
while (cin >> s && s != ".") {
int n = s.length();
vector<int> next(n + 1);
next[0] = -1;
int i = 0, j = -1;
while (i < n) {
if (j == -1 || s[i] == s[j]) {
++i; ++j;
next[i] = j;
} else {
j = next[j];
}
}
int L = n - next[n];
if (n % L == 0) {
cout << n / L << endl;
} else {
cout << 1 << endl;
}
}
return 0;
}
3.2 关键变量说明
next[n]:整个字符串的最长相等前后缀长度L = n - next[n]:最小可能周期长度n % L == 0:验证是否完整周期
4. 边界条件与测试用例分析
4.1 典型测试用例
| 输入 | 输出 | 说明 |
|---|---|---|
| ababab | 3 | 标准周期情况 |
| aaaa | 4 | 单字符重复 |
| abcabcabc | 3 | 多字符周期 |
| abac | 1 | 无周期 |
| a | 1 | 最小边界 |
| (空串) | 0 | 特殊处理 |
4.2 易错点警示
- 空字符串处理:题目通常约定非空输入,但实际编码时应考虑防御性编程
- next数组大小:必须为n+1以存储next[n]的值
- 循环终止条件:注意题目可能用"."作为输入结束标记
- 整数除法:n/L必须保证L≠0,这在n>0时由KMP性质保证
5. 算法优化与衍生问题
5.1 时间复杂度分析
- next数组构建:O(n)时间
- 周期计算:O(1)时间
- 总体复杂度:线性时间复杂度,完美满足竞赛要求
5.2 同类问题拓展
- 最短周期查找:与本题解法相同
- 所有周期查找:通过枚举L的因数
- 循环移位判断:可将两个原字符串连接后判断是否包含另一字符串
- 带通配符的周期匹配:需要结合KMP与动态规划
6. 竞赛实战技巧
- 快速手写模板:建议将KMP的getNext函数作为标准模板记忆
- 调试技巧:打印next数组验证计算是否正确
- 空间优化:对于超长字符串,可用int[]替代vector以减少开销
- 输入加速:在NOI系列竞赛中,使用ios::sync_with_stdio(false)加速输入输出
经验之谈:实际比赛中,约有30%的选手会因为next数组大小设置错误导致WA。建议在本地测试时专门构造n=1和n=2的边界用例。
7. 学习路径建议
-
先修知识:
- 掌握基础字符串操作
- 理解朴素字符串匹配算法
- 熟悉时间复杂度的计算方法
-
延伸学习:
- KMP算法的其他应用(如AC自动机基础)
- 后缀数组与后缀自动机
- 字符串哈希技巧
-
推荐练习题:
- POJ 2406 Power Strings(本题原型)
- UVA 455 Periodic Strings
- LeetCode 459. Repeated Substring Pattern
在实际编码时,我发现许多初学者容易混淆next数组的索引范围。一个实用的记忆方法是:next[i]对应的是前i个字符的子串(索引0到i-1),因此数组需要n+1的空间。这个细节在调试时可以通过打印整个next数组来验证。
