【KMP】Power Strings

该博客探讨了如何使用KMP算法解决寻找字符串s的最大幂次问题。对于给定的字符串s,目标是找到字符串a,使得s可以表示为a的某个幂次。博客提供了样例输入和输出,并给出了解决问题的C++代码实现,强调了处理大输入数据的注意事项。

描述

Given two strings a and b we define ab to be their concatenation. For example, if a = “abc” and b = “def” then ab = “abcdef”. If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = “” (the empty string) and a^(n+1) = a*(a^n).

输入

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

输出

For each s you should print the largest n such that s = a^n for some string a.

样例输入

abcd
aaaa
ababab
.

样例输出

1
4
3

提示

This problem has huge input, use scanf instead of cin to avoid time limit exceed.
题目来源

Waterloo Jun.1 2002

分析:
此题作为理解KMP算法的练习。
代码:
#include<bits/stdc++.h>
using namespace std;
int ll;
int next[1000010];
void kmp(string s)//KMP算法
{
int l=0,r=-1;
next[0]=-1;
while(l<ll)
{
if (r==-1||s[l]s[r])
{
l++;
r++;
next[l]=r;
}
else
r=next[r];//回到初位置
}
}
int main()
{
string s;
int l;
while(cin>>s)
{
if (s[0]
’.’) break;
ll=s.length();
kmp(s);
l=ll-next[ll];
if (ll%l==0)//最短子串的出现次数
cout<<ll/l<<endl;
else
cout<<1<<endl;
}
return 0;
}

### 解题思路 Power Strings 问题是经典字符串算法题,目标是找出一个字符串 `s` 最多可以由多少个相同的子串 `a` 重复连接构成,即 `s = a^n`,其中 `n` 是要找的最大值。 解决此问题的关键是使用 **KMP(Knuth-Morris-Pratt)算法** 中的 `next` 数组,它能够帮助我们找出字符串中前后缀的最长匹配长度,从而判断字符串是否由某个子串重复多次构成。 #### KMP 中的 `next` 数组 在 KMP 算法中,`next[i]` 表示模式串从开头到第 `i` 位的子串中,最长的相等前缀与后缀的长度。利用这个特性,我们可以通过 `next` 数组来判断字符串是否存在重复子串。 设字符串长度为 `len`,如果 `len % (len - next[len]) == 0`,则说明字符串是由长度为 `len - next[len]` 的子串重复构成的,重复次数为 `len / (len - next[len])`。否则,无法由同一子串重复构成,返回 `1`。 --- ### 代码实现 以下为使用 KMP 算法求解 Power Strings 问题的实现代码: ```cpp #include <iostream> #include <cstring> using namespace std; const int MAXN = 1000005; char s[MAXN]; int next_arr[MAXN]; // 构建 next 数组 void build_next(int len) { next_arr[0] = -1; int j = -1; for (int i = 1; i < len; i++) { while (j >= 0 && s[i] != s[j + 1]) { j = next_arr[j]; } if (s[i] == s[j + 1]) { j++; } next_arr[i] = j; } } int main() { while (scanf("%s", s) != EOF && s[0] != '.') { int len = strlen(s); build_next(len); int repeat_len = len - next_arr[len - 1] - 1; if (len % repeat_len == 0) { printf("%d\n", len / repeat_len); } else { printf("1\n"); } } return 0; } ``` --- ### 示例分析 以 `ababab` 为例: - `len = 6` - `next[len - 1] = 3`,即最长前缀后缀匹配长度为 3。 - `repeat_len = len - next[len - 1] - 1 = 6 - 3 - 1 = 2` - `len % repeat_len == 0`,因此 `n = 6 / 2 = 3`,表示该字符串由 `"ab"` 重复 3 次构成。 对于 `aaaa`: - `len = 4` - `next[len - 1] = 3` - `repeat_len = 1` - `4 % 1 == 0`,因此 `n = 4` 对于 `abcd`: - `next[len - 1] = 0` - `repeat_len = 4 - 0 - 1 = 3` - `4 % 3 != 0`,因此 `n = 1` --- ### 时间复杂度分析 - 构建 `next` 数组的时间复杂度为 **O(n)**。 - 主函数中判断重复次数的时间复杂度为 **O(1)**。 - 总体时间复杂度为 **O(n)**,适用于最大长度为 1,000,000 的输入。 --- ### 优化与注意事项 - 输入规模较大,应使用 `scanf` 而非 `cin` 以避免超时。 - 需要处理多个测试用例,直到遇到输入为 `.` 的情况。 - 注意 `next` 数组构建时的索引处理,避免越界。 --- ### 总结 通过 KMP 算法中的 `next` 数组,可以高效判断字符串是否由某子串重复构成,并计算最大重复次数。该方法在时间复杂度和空间复杂度上都表现优异,适合处理大规模输入数据。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值