其他系列文章导航
文章目录
前言
这是力扣的1071题,难度为简单,解题方案有很多种,本文讲解我认为最奇妙的两种。
一、题目描述
对于字符串 s
和 t
,只有在 s = 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
由大写英文字母组成
二、题解
2.1 方法一:辗转处理
思路与算法:
我们可以把str1看作n个T,str2看作m个T。
str1+str2=(m+n)T=(n+m)T=str2+str1
然后我们保证str1的长度大于str2,str1每次减掉个str2,最后保证str2为" "就可以了。
如果最后或者过程中,str1不等于str2,则没有最大公因子
第一种情况例如:
- ABCABC ABC 减一次
- ABC ABC 减第二次
- " " ABC 保证str1的长度大于str2
- ABC " " ------->ABC
第二种情况例如:
- ABABAB ABAB 减一次
- AB ABAB 保证str1的长度大于str2
- ABAB AB 减第二次
- AB AB 减第三次
- " " AB 保证str1的长度大于str2
- AB " " ------->ABC
2.2 方法二:gcd 算法
gcd 算法:
const gcd = (a, b) => (0 === b ? a : gcd(b, a % b))
如果它们有公因子 abc,那么 str1 就是 m 个 abc 的重复,str2 是 n 个 abc 的重复,连起来就是 m+n个 abc,好像 m+n 个 abc 跟 n+m 个 abc 是一样的。
所以如果 str1 + str2 === str2 + str1 就意味着有解。
我们也很容易想到 str1 + str2 !== str2 + str1 也是无解的充要条件。
当确定有解的情况下,最优解是长度为 gcd(str1.length, str2.length) 的字符串。
三、代码
3.1 方法一:辗转处理
Java版本:
class Solution { public static void main(String[] args) { String str1 = "ABCDEF", str2 = "DEF"; System.out.println(gcdOfStrings(str1, str2)); } public static String gcdOfStrings(String str1, String str2) { if (str1.length() < str2.length()) return gcdOfStrings(str2, str1);//保证str1的长度大于str2 if (str2.isEmpty()) return str1;//str1被删空后换位,则换位后的str1是最大公因子 if (!str1.startsWith(str2)) return ""; return gcdOfStrings(str1.substring(str2.length()), str2); } }
C++版本:
class Solution { public: static string gcdOfStrings(string str1, string str2) { if (str1.length() < str2.length()) return gcdOfStrings(str2, str1);//保证str1的长度大于str2 if (str2.empty()) return str1;//str1被删空后换位,则换位后的str1是最大公因子 if (str1.find(str2) != 0) return ""; return gcdOfStrings(str1.substr(str2.length()), str2); } };
3.2 方法二:gcd 算法
Java版本:
class Solution { public String gcdOfStrings(String str1, String str2) { if (!(str1 + str2).equals(str2 + str1)) return ""; int len1 = str1.length(); int len2 = str2.length(); while (len1 != len2) { if (len1 > len2) { len1 -= len2; } else { len2 -= len1; } } return str1.substring(0, len1); } }
C++:
class Solution { public: std::string gcdOfStrings(std::string str1, std::string str2) { if (str1 + str2 != str2 + str1) return ""; int len1 = str1.length(); int len2 = str2.length(); while (len1 != len2) { if (len1 > len2) { len1 -= len2; } else { len2 -= len1; } } return str1.substr(0, len1); } };
四、复杂度分析
时间复杂度:O(n) ,字符串拼接比较是否相等需要 O(n) 的时间复杂度,求两个字符串长度的最大公约数需要 O(logn) 的时间复杂度,所以总时间复杂度为 O(n+logn)=O(n) 。
空间复杂度:O(n) ,程序运行时建立了中间变量用来存储 str1 与 str2 的相加结果。