分析: 题意为给出两个字符串,求其公共循环节的数目,那么首先要求出其公共最小循环节!这里需要用到Kmp算法中的SetNext()函数来求循环节。
关键步骤: 1.SetNext()函数:(将第一个重复位之前的所有位的值赋为-1,然后第一个重复位从0开始,之后匹配失败也赋值为0)
void SetNext(char s[])
{
int j=-1,i;
Next[0]=-1;
int len=strlen(s);
for(i=1;i<len;i++)
{
while(j>=0&&s[i]!=s[j+1])
j=Next[j];
if(s[i]==s[j+1])
j++;
Next[i]=j;
}
}
2.求字符串最短循环节:(与上面SetNext函数一块用)
void recycle (char s[])
{
int len = str(s);
int length = 0;//最短循环节长度
if(len % ( len - Next[len-1]-1 ) ==0)
length = len - Next[len-1];
else
length = len;
//创建最短循环节字符串
for(int i=0;i<length;i++)
{
rec[i] = s[i];
}
题解: 求出最短循环节长度length后,再求出原来两个字符串长度的最大公约数max,然后不断叠加length,直到length大于max,过程中如果叠加得到的结果能整除两个字符串长度就说明这也是一个公共循环节。
完整代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
char a[112345];
char b[112345];
char c[112345];
int Next[112345];
int M,N;
int NN;
int cc;
void SetNext(char s[])
{
int j=-1,i;
Next[0]=-1;
int len=strlen(s);
for(i=1;i<len;i++)
{
while(j>=0&&s[i]!=s[j+1])
j=Next[j];
if(s[i]==s[j+1])
j++;
Next[i]=j;
}
}
void circle(char s[])
{
cc=0;
if( NN%(NN-Next[NN-1]-1) == 0 )
cc = NN-Next[NN-1]-1;
else
cc = NN;
for(int i=0;i<cc;i++)
c[i] = s[i];
}
int Kmp(char x[],char y[])
{
int cnt = 0;
int i=0,j=0;
while(i<N)
{
if(x[i]==y[j])
i++, j++;
else
return -1;
if(j==cc)
{
j = 0;
cnt++;
}
}
return cnt;
}
int gcd(int a, int b)
{
return b==0? a : gcd(b, a%b);
}
int main()
{
scanf("%s", a);
scanf("%s", b);
int tmp;
if(strlen(a)>=strlen(b))
{
N = strlen(a);
NN = strlen(b);
SetNext(b);
circle(b);
tmp = Kmp(a, c);
}
else
{
N = strlen(b);
NN = strlen(a);
SetNext(a);
circle(a);
tmp = Kmp(b, c);
}
int ans=0;
if(tmp>0)
{
int mm = gcd(N,NN);
int d = cc;
while(cc<=mm)
{
if( N%cc == 0 && NN %cc == 0)
{
ans++;
}
cc+=d;
}
}
cout << ans << endl;
return 0;
}