UVa455周期串(Periodic Strings)
这题有点意思:
1.我设计了伪代码
k=1
while (k<len):
s1=s.substr(k-1,k)
for i=0 to len-1:
if(s1 != s.substr(i*k+k,k)):
isfind=false
break
if(isfind) break;
k++
于是基于以上设计,代码如下:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
while(n--){
string s;
cin>>s;
int len=s.length();
int k=1;
bool isfind=true;
while(k<len){
isfind=true;
string s1=s.substr(0,k);
for(int i=0;i<len;i++){
if(s1 != s.substr(k*i+k,k)){
isfind=false;
break;
}
}
if(isfind) break;
else k++;
}
cout<<k<<endl;
}
return 0;
}
结果错了,连测试用例都没有正确输出!
2.偷了个懒,丢给AI帮我分析哪里逻辑错了
错误1:子串起始位置错误
当 i = 0 时,k*i + k = k,即从第 k 个字符开始取子串,跳过了第一个周期(本应比较第2、3…个周期)。
当 i = 1 时,起始位置为 2k,依此类推。
但由于循环条件 i < len,当 k 较小时,i 会一直增加到接近 len,导致 k*i + k 远超字符串长度,substr 会抛出异常(或返回空串),使比较永远失败。
错误2:越界与遗漏比较
正确的做法应该是:从第 k 个字符开始,每隔 k 取一个子串,共取 len/k - 1 次(因为第一个周期已经作为模板)。
你的循环次数和索引计算都不符合这个逻辑,最终导致即使字符串具有周期 k,也会被判为假。
按照建议我修改了自己的代码如下:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
while(n--){
string s;
cin>>s;
int len=s.length();
int k=1;
bool isfind=true;
while(k<len){
isfind=true;
string s1=s.substr(0,k);
for(int i=1;i*k<len;i++){
if(s1 != s.substr(k*i,k)){
isfind=false;
break;
}
}
if(isfind) break;
else k++;
}
cout<<k<<endl;
if(n) cout<<endl;
}
return 0;
}
过了,然而rank排名在7615!
3.叫AI给我分析如何进行优化,于是:
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
while (n--) {
string s;
cin >> s;
int len = s.size();
int period = len; // 默认周期为全长
// 只检查 len 的因数
for (int k = 1; k <= len / 2; ++k) {
if (len % k != 0) continue; // 长度不能整除,不可能为周期
bool ok = true;
for (int i = k; i < len; ++i) {
if (s[i] != s[i % k]) {
ok = false;
break;
}
}
if (ok) {
period = k;
break;
}
}
cout << period << "\n";
if (n) cout << "\n";
}
return 0;
}
这样rank排名居然是7616!
我感觉上了一个当,然后继续进行追问如何优化,结果我看使用了KMP算法——
#include <stdio.h>
#include <string.h>
int main() {
int n, len, i, j, period;
char s[100];
scanf("%d", &n);
while (n--) {
scanf("%s", s);
len = strlen(s);
// 计算 KMP 的 next 数组
int next[100] = {0};
for (i = 1, j = 0; s[i]; i++) {
while (j > 0 && s[i] != s[j]) j = next[j-1];
if (s[i] == s[j]) j++;
next[i] = j;
}
period = len - next[len-1];
if (len % period != 0) period = len;
printf("%d\n", period);
if (n) printf("\n");
}
return 0;
}
然而系统排名仍然是7616!
试了好几遍,系统给我的邮件让我很吃惊,真是简洁和友好!

也不用纠结了,这是一道简单题而已~
本文来自博客园,作者:qiannong,转载请注明原文链接:https://www.cnblogs.com/qiannong/p/20302896

浙公网安备 33010602011771号