题目来自LeetCode,链接:字符串的最大公因子。具体描述为:对于字符串 S 和 T,只有在 S = T + … + T(T 与自身连接 1 次或多次)时,我们才认定 “T 能除尽 S”。返回最长字符串 X,要求满足 X 能除尽 str1 且 X 能除尽 str2。
示例1:
输入:
输入:str1 = "ABCABC", str2 = "ABC"
输出:"ABC"
示例2:
输入:str1 = "ABABAB", str2 = "ABAB"
输出:"AB"
示例2:
输入:str1 = "LEET", str2 = "CODE"
输出:""
这道题可以直接用辗转相除法来做,无非就是将对数的处理(取模操作)改为对字符串的操作。在辗转相除法里最重要的公式就是gcd(a,b)=gcd(b,a%b)
,所以这里只需要处理字符串的“取模”操作即可,比如示例2中的str1 = "ABABAB"
对str2 = "ABAB"
取模就应该得到AB
,不过取模前需要判断str1
在索引k*str2.length
之前的字符串是否为k
个str2
,不是的话可以直接判断没有公约数了。
总共的字符串比较需要 O ( N ) O(N) O(N)(N为两个字符串长度之和),即为时间复杂度,空间复杂度为中间一些临时字符串占用空间,也是 O ( N ) O(N) O(N)。
JAVA版代码如下:
class Solution {
public String gcdOfStrings(String str1, String str2) {
int sLen1 = str1.length(), sLen2 = str2.length();
if (sLen1 < sLen2) {
return gcdOfStrings(str2, str1);
}
int n = sLen1 / sLen2;
for (int i = 0; i < n; ++i) {
if (!str2.equals(str1.substring(i * sLen2, (i + 1) * sLen2))) {
return "";
}
}
if (sLen1 % sLen2 == 0) {
return str2;
}
return gcdOfStrings(str2, str1.substring(n * sLen2));
}
}
提交结果如下:
Python版代码如下:
class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
sLen1, sLen2 = len(str1), len(str2)
if sLen1 < sLen2:
return self.gcdOfStrings(str2, str1)
n = sLen1 // sLen2
for i in range(n):
if not str2 == str1[i * sLen2 : (i + 1) * sLen2]: #取模操作前需判断是否能取模
return ''
if sLen1 % sLen2 == 0:
return str2
return self.gcdOfStrings(str2, str1[n * sLen2 :]) #第二个参数即为取模之后的字符串
提交结果如下: