给两个字符串a和b,求一个最长字符串c,使得a和b都可以由c组成.
例如示例一,a可以有两个"ABC"组成,而b可以由一个"ABC"组成,所以得出最长公因子c是"ABC".
在示例二中,a可以由三个"AB"组成,b可以由两个"AB"组成,所以得出最长公因子c是"ABC".
而示例三中,找不出任何一个字符串可以同时组成a和b,因此返回空字符串.
由于字符串c可以同时组成a和b,因此我们可以判断出c的长度范围为1到a和b中最短的长度之间,并且c可以同时整除a和b的长度.
以示例二为例,字符串a的长度为6,字符串b的长度为4,因此可以断定c的长度范围在1~4之间,而且a和b的长度需要被c的长度整除,因此我们可以将c的长度范围控制锁定在 1,2 中(3和4不能同时整除4和6),这时候我们把a的开头1个长度的字符串和2个长度的字符串拎出来,如果有可以同时组成a和b的字符串(若有多个满足选最大的)则是a和b的最大公因子.
//传入可能可以匹配的字符串c(此处形参名为t),以及待匹配的字符串a或b(此处形参名为s)
bool check(string t,string s){
int lenx = s.size() / t.size(); //这边计算需要多少个t的长度才能达到s的长度
string ans = "";
for (int i = 1; i <= lenx; ++i){//不断累加直至匹配字符串长度与待匹配字符串长度一致
ans = ans + t;
}
//直接返回累加后的匹配字符串是否与待匹配字符串相同
return ans == s;
}
遍历c的长度范围,在确定c的长度后,把a(或者b也可以)开头与c长度相同的字符串不断自身累加直到,长度分别和a,b一样,再进行比较,如果二者都可以匹配,这表示该长度满足条件.
这里有个小技巧就是在c的长度范围中从较大的数开始遍历,如果是从小开始遍历,保不准后面有更大的满足条件的字符串长度,而从大开始遍历,返回第一个满足条件的即可.
string gcdOfStrings(string str1, string str2) {
int len1 = str1.size(), len2 = str2.size();
for (int i = min(len1, len2); i >= 1; --i){ // 从长度大的开始枚举可以减少查询次数
//若是待定长度无法同时整除两个字符串的长度则跳过,因为不可能可以拼接组成
if (len1 % i == 0 && len2 % i == 0){
string X = str1.substr(0, i); //取出待匹配字符串
if (check(X, str1) && check(X, str2)) return X; //当二者都可以被待匹配字符串组成,则直接返回
}
}
return ""; //若是没有一个字符串满足条件则返回空字符串
}
完整代码+提交结果如下: