对于字符串 s
和 t
,只有在 s = t + t + t + ... + t + t
(t
自身连接 1 次或多次)时,我们才认定 “t
能除尽 s
”。
给定两个字符串 str1
和 str2
。返回 最长字符串 x
,要求满足 x
能除尽 str1
且 x
能除尽 str2
。
示例 1:
输入:str1 = "ABCABC", str2 = "ABC" 输出:"ABC"
示例 2:
输入:str1 = "ABABAB", str2 = "ABAB" 输出:"AB"
示例 3:
输入:str1 = "LEET", str2 = "CODE" 输出:""
提示:
1 <= str1.length, str2.length <= 1000
str1
和str2
由大写英文字母组成
class Solution {
public String gcdOfStrings(String str1, String str2) {
// 获取两个字符串的长度
int len1 = str1.length();
int len2 = str2.length();
// 从较小的字符串长度开始,逐渐减小,直到找到一个合适的最大公约字符串
for (int i = Math.min(len1, len2); i >= 1; i--) {
// 检查当前长度 i 是否同时是 str1 和 str2 的长度的约数
if (len1 % i == 0 && len2 % i == 0) {
// 取出当前长度 i 的前缀字符串
String X = str1.substring(0, i);
// 验证当前前缀字符串 X 是否是 str1 和 str2 的公共子串
if (check(X, str1) && check(X, str2)) {
// 如果 X 满足条件,则返回 X 作为两个字符串的最大公约字符串
return X;
}
}
}
// 如果没有找到合适的最大公约字符串,则返回空字符串
return "";
}
// 验证字符串 s 是否是由 t 反复拼接得到的
public boolean check(String t, String s) {
// 计算 t 在 s 中应该重复的次数
int lenx = s.length() / t.length();
StringBuffer ans = new StringBuffer();
// 将 t 重复 lenx 次,形成新的字符串 ans
for (int i = 0; i < lenx; i++) {
ans.append(t);
}
// 判断 ans 是否与 s 相等
return ans.toString().equals(s);
}
}
解题思路
-
理解问题:
- 你需要找到两个字符串
str1
和str2
的最大公约字符串,即能够同时整除两个字符串的最大前缀。
- 你需要找到两个字符串
-
确定长度:
- 计算
str1
和str2
的长度,找出两者中较小的长度,以此为起点逐步检查可能的公约字符串。
- 计算
-
检查所有可能的前缀:
- 从较小的长度开始,逐渐减小(检查前缀长度从
Math.min(len1, len2)
到 1),尝试用每个长度的前缀构造一个字符串,然后检查这个前缀是否能完全由该字符串构成。
- 从较小的长度开始,逐渐减小(检查前缀长度从
-
前缀验证:
- 对于每个前缀
X
,验证它是否能被str1
和str2
完全拼接而成。这个过程通过check
方法实现,该方法将前缀X
重复拼接到与原字符串长度相等,然后比较结果。
- 对于每个前缀
-
返回结果:
- 如果找到了符合条件的前缀,返回它。如果没有找到,返回空字符串。
辅助方法 check
的作用
-
拼接字符串:
- 该方法接受一个前缀
t
和一个目标字符串s
,它会将前缀t
重复拼接到与s
相同的长度,并检查生成的字符串是否与s
相等。
- 该方法接受一个前缀
-
验证逻辑:
- 如果生成的字符串与目标字符串
s
相等,说明s
是由前缀t
反复拼接得到的,否则不是。
- 如果生成的字符串与目标字符串
这种方法通过检查所有可能的前缀,从而确保找到的公约字符串是最大长度的。