String 字符串
String的最短重复字段
今天做codeforces遇到的一道题,感觉很有意思,虽然有更好的做法,但是为例找一下最短重复子串也是挺有意思的。
原题连接:https://codeforces.com/contest/1473/problem/B
我们在这里就说一下找一个字符串的最短重复字段吧,假设一个字符串s的字符长度是10,那么他的重复字段的长度就是1,2,5,10这几种情况,比如说aaa,他就是由字段a重复构成;bcbcbc,它由子段bc重复构成;abc除了他本身就没有其他子序列重复构成了,所以也就是由abc重复构成。所以一个字符串找他的最短重复字段,他的长度也肯定是字符串长度的因子,所以我们在找他的重复子串的时候可以先判断子串的长度是否能整除字符串的长度,如果不能够被整除,那么也就没有对比判断的必要了。
假设有一个字符串abcabc,我们先假设重复子串的长度是1,那我们就每隔(1-1)个进行一次对比,第一次我们对比a和b,发现不匹配,然后我们就假设子串长度是2,2能整除6,所以继续向下运行,我们每隔(2-1)个字符进行一次对比,我们对比a和c,发现不匹配,退出继续向下寻找,我们假设长度是3,3是6的因子,我们每隔(3-1)个字符进行对比,第一次我们对比第一个和第四个,对比成功,再加3就超过了原字符串的长度,退出,查找第二个与第五个是否匹配,匹配继续往下寻找,直到大于原字符串的长度……重复寻找3次(子串的长度是3),如果都匹配成功就返回这个字符串;
寻找重复字串完整代码如下:
string gcd(string s){
int len = s.length();
for(int i=1;i<=len;i++){//假设子串的长度是i
int flag = 0;
if(len%i==0){//如果i是原串长度的因数才继续往下寻找
for(int j=0;j<i;j++){//匹配i次
int wei = j;
while(wei<len){
if(s[wei]!=s[j]){
flag = 1;
break;
}
wei+=i;
}
if(flag) break;
}
if(flag==0){//完全匹配完成
string ans;
for(int j=0;j<i;j++){
ans += s[j];
}
return ans;
}
}
}
return s;
}
原题的完整代码如下:
#include<iostream>
#include<string>
using namespace std;
string gcd(string s){
int len = s.length();
for(int i=1;i<=len;i++){
int flag = 0;
if(len%i==0){
for(int j=0;j<i;j++){
int wei = j;
while(wei<len){
if(s[wei]!=s[j]){
flag = 1;
break;
}
wei+=i;
}
if(flag) break;
}
if(flag==0){
string ans;
for(int j=0;j<i;j++){
ans += s[j];
}
return ans;
}
}
}
return s;
}
int GCD(int a,int b){
if(b==0)return a;
return GCD(b,a%b);
}
int LCM(int a,int b){
return a*b/GCD(a,b);
}
int main(){
int t;
cin >> t;
while(t--){
string a,b;
cin >> a >> b;
string agcd = gcd(a);
string bgcd = gcd(b);
if(agcd==bgcd){
int m1 = a.length()/agcd.length();
int m2 = b.length()/bgcd.length();
if(m1<m2){
int l = m1;m1 = m2;m2 = l;
}
if(m1%m2==0){
if(a.length()>b.length()) cout << a << endl;
else cout << b << endl;
}
else{
string ans = "";
int lcm = LCM(m1,m2);
for(int i=0;i<lcm;i++){
ans+=agcd;
}
cout << ans << endl;
}
}
else cout << "-1" << endl;
}
return 0;
}