子串循环问题
Description
给定一个字符串,求需要添加至少几个字符到字符串末尾才能使得整个字符串由某一个不为本身的子串循环构成? 如“abca”,添加“bc”后构成“abcabc”,其由子串“abc”循环构成;也可以添加“abca”后构成“abcaabca”,其由子串“abca”循环构成,相比之下“bc”只有2个字符,添加的字符量最少。
Input
第一行包括一个整数T(1 <= T <= 100)
,代表测试组数
每组测试数据包括一行字符串,其长度范围为 [3, 10^4]
Output
对于每组测试数据
输出一个整数N,代表添加的最小字符数量
Sample
Input
Output
4
aaa
abca
abcdefg
abcabcabca0
2
7
2
代码实现1:朴素算法,较麻烦且代码量多,但相对新手更容易理解
#include<iostream>
using namespace std;
//朴素算法,较麻烦
int loopCheck(string str){
int len = (int)str.length(),ans=0,check,lastpos=0;
//进行“除结尾串外,前面有无循环串”的判断
int i = 0;
int j = 0;
while(i<len-i){
j=0;
i++;
string subloop = str.substr(0,i);
check = 0;
while(j+i<len-i){
if(j==0)check = 1;
j+=i;
string subtemp = str.substr(j,i);
if(subloop!=subtemp){
check = 0;
break;
}
}
//除结尾串外,前面有循环串
if(check){
lastpos = j+i;
int k = 0;
while(k<(int)subloop.length()&&len-1-(lastpos+k)>=0){
//结尾串跟前面循环串不一致,进入无循环串判断环节
if(subloop[k]!=str[lastpos+k]){
//嵌套check;
check = 0;
break;
}
k++;
}
//
if(check){
return (int)subloop.length()-k;
}
}
}
//无循环串,判断开头和结尾有无相同串
int l = 0;
int maxlen = 0;
string strRec;
while(l<len/2+1){
l++;
string t1 = str.substr(0,l);
string t2 = str.substr(len-l,l);
if(t1==t2 && l>maxlen){
maxlen = l;
}
}
return len-maxlen*2;
}
int main(){
string str;
int t;
cin >> t;
while(t--){
cin>>str;
cout<<loopCheck(str)<<endl;
}
}
代码实现2:KMP算法,写量少
以下为思路
先是字串循环的定律。
设该字符串为str,长度为p_len。
经过kmp算法处理后可得到一个next数组,数组中共有p_len+1个元素。
如果str存在最小循环节,则它的长度为L = len-next[p_len];
如果p_len可以被p_len-next[p_len]整除(即p_len%(p_len-next[lenp_len)==0),说明该字符串由循环字节组成。
若next[p_len]=0,说明只需要再尾部加上一个该字符串的最小循环节即可,此时返回p_len;如果不为0说明只能加上它自己才能构成一个字串循环,此时返回0即可。
如果不能被整除,说明需要补上几个字母才行,需要补的字母个数为p_len-next[p_len]-(next[p_len]%(p_len-next[p_len]))个。
#include<iostream>
using namespace std;
//KMP实现,高效简洁
int KMPGetLoop(string p)
{
int p_len = (int)p.length();
//获取next数组
int next[p_len+1];
next[0] = -1;
int i = 0;
int j = -1;
while (i < p_len)
{
if (j == -1 || p[i] == p[j])
{
next[++i] = ++j;
}
else
{
j = next[j];
}
}
//辅助思考用
// for(int i = 0; i < p_len+1; i++){
// cout<<next[i]<<" ";
// }
// cout<<endl;
//计算重复字串
if (p_len % (p_len - next[p_len]) == 0)
{
if (next[p_len] == 0)
{
return p_len;
}
else
{
return 0;
}
}
else
{
return p_len-next[p_len]-(next[p_len]%(p_len-next[p_len]));
}
return -1;
}
int main(){
string str;
int t;
cin >> t;
while(t--){
cin>>str;
cout<<KMPGetLoop(str)<<endl;
}
}