Leetcode 1071. Greatest Common Divisor of Strings

Problem Explanation

The problem requires you to find the largest string X that divides two given strings str1 and str2. A string X is said to divide another string Y if string Y can be made by concatenating string X with itself one or more times.

Let's take an example:

If str1 = "ABCABC", and str2 = "ABC", the largest common string X that divides both str1 and str2 is "ABC". That's because "ABC" can be concatenated with itself to form "ABCABC" (that is str1) and it is equal to str2.

However, if str1 = "LEET" and str2 = "CODE", there is no common string that divides both the strings, hence the output should be "".

Approach Explanation

We start from the longest possible common string, which is str2. Then, we subtract the occurrence of this string from str1 and continue the process by checking the remaining string in str1 with str2 again. We continue subtracting and comparing until the remaining string in str1 does not start with str2. After every subtraction and comparison, we update str1 to be the remainder and str2 to be the current str2. We continue the subtraction and comparison process recursively until str2 is an empty string, in which case we get the result as the final remaining string in str1.

The main functions used here are find() and substr(). The find() function searches str2 in str1, and if not found, returns a special constant string::npos. The substr() function returns a new string that is a copy of a sub-string of original string.

Example

Let's illustrate the above approach with an example:

Consider str1 = "ABCABC" and str2 = "ABC".

Currently, str2 is found in str1, hence we subtract the occurrence of str2 from str1 by using substr() function. Now str1 = "" and str2 = "ABC" again.

Now, str1 is empty. Hence, we can't find str2 in str1 so we return empty string "".

Then we call the recursive function gcdOfStrings() again with str2 = "ABC" and str1 = "". This time str2 is not an empty string, but str1 is an empty string. Hence, we return str2 which is "ABC". Finally we get the output as "ABC" which is the largest common string that divides both str1 and str2.

Python Solution

1
2python
3class Solution:
4    def gcdOfStrings(self, str1: str, str2: str) -> str:
5        if len(str1) < len(str2):
6            return self.gcdOfStrings(str2, str1)  # Make sure str1 is not shorter than str2.
7        elif not str1.startswith(str2):  # impossible for str2 to divides str1
8            return ''
9        elif str2 == '':
10            return str1
11        else:
12            return self.gcdOfStrings(str2, str1[len(str2):]) 

Java Solution

1
2java
3class Solution {
4    public String gcdOfStrings(String str1, String str2) {
5        if (str1.length() < str2.length()) {
6            return gcdOfStrings(str2, str1);
7        } 
8        else if (!str1.startsWith(str2)) {
9            return "";
10        } 
11        else if (str2.isEmpty()) {
12            return str1;
13        } 
14        else {
15            return gcdOfStrings(str2, str1.substring(str2.length()));
16        }
17    }
18}

Javascript Solution

1
2javascript
3var gcdOfStrings = function(str1, str2) {
4    if (str1.length < str2.length) {
5        return gcdOfStrings(str2, str1);
6    } 
7    else if (!str1.startsWith(str2)) {
8        return '';
9    }
10    else if (str2 === '') {
11        return str1;
12    }
13    else {
14        return gcdOfStrings(str2, str1.slice(str2.length));
15    }
16};

C++ Solution

1
2cpp
3class Solution {
4public:
5    string gcdOfStrings(string str1, string str2) {
6        if (str1.length() < str2.length()) {
7            return gcdOfStrings(str2, str1);
8        }
9        else if (str1.find(str2) != 0) {
10            return "";
11        }
12        else if (str2.empty()) {
13            return str1;
14        }
15        else {
16            return gcdOfStrings(str2, str1.substr(str2.length()));
17        }
18    }
19};

C# Solution

1
2csharp
3public class Solution {
4    public string GcdOfStrings(string str1, string str2) {
5        if (str1.Length < str2.Length) {
6            return GcdOfStrings(str2, str1);
7        }
8        else if (!str1.StartsWith(str2)) {
9            return "";
10        }
11        else if (str2 == "") {
12            return str1;
13        }
14        else {
15            return GcdOfStrings(str2, str1.Substring(str2.Length));
16        }
17    }
18}

The above solutions for Python, Java, JavaScript, C++, and C# all effectively solve the problem by finding the longest string that divides both given strings. This is accomplished through a process of subtraction and comparison that goes back and forth between the two strings until the divider string is found or it is determined that no such string exists.

This algorithm has a time complexity of O(N), where N is the length of the string. This is because both the find() and substr() or equivalent functions have a linear time complexity. The space complexity of the algorithm is also O(N) because a new string is created in each recursive call.

In conclusion, the problem of finding a string that divides two other strings can be efficiently solved using the recursive approach. This solution works for any programming language that supports string manipulation and specific string methods such as startsWith(), substr(), or an equivalent. Any discrepancies in the specific syntax or built-in methods are easily adjusted for based on the specific language being used. This makes it a highly efficient and versatile solution to this common string manipulation problem.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫