解題思路
定理:兩個整數(shù)的最大公約數(shù)等于其中較小的那個數(shù)和兩數(shù)相除余數(shù)的最大公約數(shù)。最大公約數(shù)(Greatest Common Divisor)縮寫為GCD。
gcd(a,b) = gcd(b,a mod b) (不妨設(shè)a>b 且r=a mod b ,r不為0)
gcd(a,b) = b if a%b == 0 else gcd(b,a%b)
或者
gcd(a,b) = a if b==0 else gcd(b,a%b)
注意到一個性質(zhì):如果存在一個符合要求的字符串 X,那么也一定存在一個符合要求的字符串 X',它的長度為 str1 和 str2 長度的最大公約數(shù)。
簡單來說,我們已經(jīng)知道符合條件的長度出現(xiàn)在 gcd(len_1, len_2)的所有約數(shù)中,我們假設(shè)其中一個滿足條件的約數(shù)為x,該長度為 len_x的前綴串 X 能經(jīng)過若干次拼接后得到 str1 和 str2。拿 str1 舉例,X 經(jīng)過 len_1/len_x 次拼接后得到了 str1,而 X 又能經(jīng)過 gcd(len_1, len_2)/len_x 次拼接后得到長度為 gcd(len_1,len_2)的前綴串 X',所以我們可以每次取出 gcd(len_1, len_2)/len_x 個 X 來用 X'完成替換,最后 str1 會被替換成 len_1/gcd(len_1,len_2) 個 X',str2 同理可得。因此如果存在一個符合要求的字符串 X,那么也一定存在一個符合要求的字符串 X',它的長度為 str1 和 str2 長度的最大公約數(shù)。我們只需要判斷長度為 gcd(len_1,len_2)的前綴串是否滿足要求即可。
算法
由上述性質(zhì)我們可以先用輾轉(zhuǎn)相除法求得兩個字符串長度的最大公約數(shù) gcd(len_1,len_2),取出該長度的前綴串,判斷一下它是否能經(jīng)過若干次拼接得到 str1 和 str2 即可。
復(fù)雜度分析:
時間復(fù)雜度:O(n),其中 n 是兩個字符串的長度范圍,即 len_1 + len_2 。判斷最大公約數(shù)長度的前綴串是否符合條件需要 O(n) 的時間復(fù)雜度,求兩個字符串長度的最大公約數(shù)需要 )O(logn) 的時間復(fù)雜度,所以總時間復(fù)雜度為 O(n+logn)=O(n)。
空間復(fù)雜度:O(n),比較的過程中需要創(chuàng)建一個長度創(chuàng)建長度為 O(n) 的臨時字符串變量,所以需要額外 O(n) 的空間。
代碼
class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
m, n = len(str1), len(str2)
if m < n:
return self.gcdOfStrings(str2, str1)
def gcd(a,b):
return b if a%b==0 else gcd(b, a%b)
r = gcd(m, n)
if (str1[:r] == str2[:r] and str1[:r]*(len(str1)//r) == str1 and str2[:r]*(len(str2)//r) == str2):
return str1[:r]
return ""