[LeetCode] 1071. Greatest Common Divisor of Strings 字符串的最大公因子



For two strings s and t, we say "t divides s" if and only if s = t + ... + t  (t concatenated with itself 1 or more times)

Given two strings str1 and str2, return the largest string x such that x divides both str1 and str2.

Example 1:

Input: str1 = "ABCABC", str2 = "ABC"
Output: "ABC"

Example 2:

Input: str1 = "ABABAB", str2 = "ABAB"
Output: "AB"

Example 3:

Input: str1 = "LEET", str2 = "CODE"
Output: ""

Example 4:

Input: str1 = "ABCDEF", str2 = "ABC"
Output: ""

Constraints:

  • 1 <= str1.length <= 1000
  • 1 <= str2.length <= 1000
  • str1 and str2 consist of English uppercase letters.

這道題定義了一種兩個字符串s和t之間的整除關系,若s串可由若干個t串組成,則說t串可以整除s串。現在給了兩個字符串 str1 和 str2,現在讓找到一個最大的字符串x,使得其可以同時整除這兩個字符串。來分析一下,由於這個x會重復出現在字符串中,所以其一定是個前綴,則字符串的所有前綴都有可能是這個x,於是乎只要遍歷所有的前綴,然后來驗證其是否可以整除這兩個字符串就可以找到要求的x了。遍歷 str1 的所有前綴,若 str1 的長度不是這個前綴的長度的整數倍,或者 str2 的長度不是這個前綴長度的整數倍,直接跳過。否則直接分別復制前綴直到和 str1,str2 的長度相同,再比較,若完全一樣,則說明前綴是一個x,賦值給結果 res。這樣遍歷下來就能得到長度最長的x了,參見代碼如下:


解法一:

class Solution {
public:
    string gcdOfStrings(string str1, string str2) {
        string res;
        int m = str1.size(), n = str2.size();
        for (int i = 0; i < m; ++i) {
            if (m % (i + 1) != 0 || n % (i + 1) != 0) continue;
            string pre = str1.substr(0, i + 1), target1, target2;
            for (int j = 0; j < m / (i + 1); ++j) {
                target1 += pre;
            }
            if (target1 != str1) continue;
            for (int j = 0; j < n / (i + 1); ++j) {
                target2 += pre;
            }
            if (target2 != str2) continue;
            res = pre;
        }
        return res;
    }
};

這道題用遞歸來做的話會變的異常的簡潔,我們仔細來觀察題目中給的例子,若存在這樣的x的話,那么短的字符串一定是長的字符串的子串,比如例子1和例子2。這樣的話其實是可以化簡的,當長串中的前綴(和短串的長度相同)不等於短串的時候,說明x不存在,可以直接返回空,否則從長串中取出和短串長度相同的前綴,繼續調用遞歸,直到其中一個為空的時候,返回另一個就可以了,參見代碼如下:


解法二:

class Solution {
public:
    string gcdOfStrings(string str1, string str2) {
        if (str1.size() < str2.size()) return gcdOfStrings(str2, str1);
        if (str2.empty()) return str1;
        if (str1.substr(0, str2.size()) != str2) return "";
        return gcdOfStrings(str1.substr(str2.size()), str2);
    }
};

下面這種解法一行搞定碉堡了,由於 str1 和 str2 可以被同一個x串整除,那么 str1+str2 和 str2+str1 一定是相同的,不信大家可以自行帶例子去驗證。而且最大的x的長度是 str1 和 str2 長度的最大公約數相同(是不是感覺很神奇,求大佬證明),這樣的話直接濃縮到一行就搞定了,參見代碼如下:


解法三:

class Solution {
public:
    string gcdOfStrings(string str1, string str2) {
        return (str1 + str2 == str2 + str1) ? str1.substr(0, gcd(str1.size(), str2.size())) : "";
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1071


參考資料:

https://leetcode.com/problems/greatest-common-divisor-of-strings/

https://leetcode.com/problems/greatest-common-divisor-of-strings/discuss/307242/C%2B%2B-3-lines

https://leetcode.com/problems/greatest-common-divisor-of-strings/discuss/303759/My-4-Lines-C%2B%2B-Solution

https://leetcode.com/problems/greatest-common-divisor-of-strings/discuss/303781/JavaPython-3-3-codes-each%3A-Recursive-iterative-and-regex-w-brief-comments-and-analysis.


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM