LeetCode #1071 Easy

Greatest Common Divisor of Strings

Greatest Common Divisor of Strings is LeetCode 1071 (Easy). A string t divides a string s when s is t written one or more times in a row.

Given str1 and str2, return the longest string that divides both of them, or "" if no string does.

Constraints
  • 1 <= str1.length, str2.length <= 1000
  • str1 and str2 consist of English uppercase letters.
mathstring
Open on LeetCode ↗
02

Intuition

Two questions settle the answer.

  • Is there any common block at all? If both strings are copies of the same block t, then str1 + str2 and str2 + str1 are both just copies of t, so they are equal. If the two joins differ, no common block exists.
  • How long is the longest one? A block that divides a string has a length that divides the string's length. So any common block's length divides both lengths, and the largest possible length is gcd(len(str1), len(str2)).

When the joins are equal, the prefix of that length really does divide both strings, so it is the answer.

How to spot this pattern

"Repeated some number of times" plus "largest" is divisibility language. When two objects are built from one repeating unit, the largest shared unit usually comes from the gcd of their sizes.

03

Approach

Try it first

Before reading on: if str1 = "ABABAB" and str2 = "ABAB", write out str1 + str2 and str2 + str1 and compare them. Then try "LEET" and "CODE". Which number decides how long the answer is? Aim for O(m + n).

1

Compare the two joins

If str1 + str2 != str2 + str1, return "". Two strings built from one block give the same result in either order, so a difference proves that no common block exists.

2

Take the gcd of the lengths

Compute length = gcd(len(str1), len(str2)) with Euclid's algorithm. Every common block has a length that divides both lengths, so none can be longer than this.

3

Return the prefix of that length

Return str1[:length]. Once the joins match, both strings are copies of one shortest block, and this prefix is a whole number of those blocks that fits both lengths exactly.

04

Greatest Common Divisor of Strings solution in Python | C++ | Java

▶1from math import gcd
▶2 
▶3class Solution:
▶4 def gcdOfStrings(self, str1, str2):
▶5 if str1 + str2 != str2 + str1:
▶6 return ""
▶7 length = gcd(len(str1), len(str2))
▶8 return str1[:length]
str1ABCABCstr2ABC1 + 22 + 1gcdjoin the strings both ways
str1"ABCABC"6 letters
str2"ABC"3 letters
If both strings are copies of one block, putting them together in either order gives the same string. So the first test needs no search: build str1 + str2 and str2 + str1.
str1ABCABCstr2ABC1 + 2ABCABCABC2 + 1ABCABCABCgcdstr1 + str2 and str2 + str1, 9 letters each
str1 + str2"ABCABCABC"
str2 + str1"ABCABCABC"
Blue letters come from str1 and green from str2. Both joins have the same length, 9, so they can be compared letter by letter.
str1ABCABCstr2ABC1 + 2ABCABCABC2 + 1ABCABCABCgcdall 9 letters match
joins equalyes
Every position matches, so str1 and str2 are copies of one common block. What is left is its length, and that depends only on the two lengths.
str1ABCABCstr2ABC1 + 2ABCABCABC2 + 1ABCABCABCgcd6mod3=0remainder 0 → gcd is 3
pair6, 3
remainder0
3 divides 6 exactly, so gcd = 3. A common block's length must divide both 6 and 3, so no block can be longer than 3.
str1ABCABCstr2ABC1 + 2ABCABCABC2 + 1ABCABCABCgcd3answer "ABC", 3 letters
length3
answer"ABC"
Take the first 3 letters, "ABC". The shading shows it fits 2 times into str1 and 1 time into str2 with nothing left over, and no longer block could fit both lengths.
05

Try each block length

A prefix of length k can only divide both strings if k divides both lengths, so skip any other k. For the rest, rebuild each string from copies of the prefix and compare. Going from the longest length down means the first match is the answer.

▶1class Solution:
▶2 def gcdOfStrings(self, str1, str2):
▶3 m, n = len(str1), len(str2)
▶4 for k in range(min(m, n), 0, -1):
▶5 if m % k or n % k:
▶6 continue
▶7 block = str1[:k]
▶8 if block * (m // k) == str1 and block * (n // k) == str2:
▶9 return block
▶10 return ""
06

Common pitfalls

Skipping the join check

✗ Wrong
length = gcd(len(str1), len(str2))
return str1[:length]
✓ Right
if str1 + str2 != str2 + str1:
    return ""
length = gcd(len(str1), len(str2))
return str1[:length]

The gcd of two lengths always exists, even when the letters have nothing in common. Without the check, "LEET" and "CODE" give "LEET" instead of "".

Returning the shortest common block

✗ Wrong
for k in range(1, len(str1) + 1):
    if divides(str1[:k], str1) and divides(str1[:k], str2):
        return str1[:k]
✓ Right
return str1[:gcd(len(str1), len(str2))]

The problem asks for the longest block. For "AAAA" and "AA" the shortest is "A", but "AA" also divides both, so "AA" is the answer.

Checking only that the shorter string is a prefix

✗ Wrong
if not str1.startswith(str2):
    return ""
✓ Right
if str1 + str2 != str2 + str1:
    return ""

A prefix match does not mean the same block repeats. "ABAB" starts with "ABA", yet no string divides both, and the prefix test lets the code return "A".

07

Edge cases

Same letters in a different order, such as "ABAB" and "BABA"

The joins are "ABABBABA" and "BABAABAB", which differ, so the answer is "" even though both strings repeat a 2-letter block.

The lengths share no factor, such as "AAA" and "AA"

The joins match, and gcd(3, 2) = 1, so the answer is the single letter "A": no longer block fits both a length of 3 and a length of 2.

08

Complexity

Time
O(m + n)
Space
O(m + n)
m and n are the two lengths. Building and comparing the two joins touches each character a constant number of times; Euclid's algorithm adds only O(log(min(m, n))). The joins need m + n characters each.
09

Greatest Common Divisor of Strings FAQ

Why is the gcd prefix guaranteed to divide both strings?

Equal joins mean str1 and str2 commute, and two strings that commute are both copies of one shortest block u. Each length is then a multiple of len(u), so their gcd is too. A prefix whose length is a multiple of len(u) is whole copies of u, and it fits each length exactly.

Can I solve it without building the joined strings?

Yes. Take the prefix t of length gcd(m, n) and check that str1 and str2 are each t repeated m / len(t) and n / len(t) times. It is still O(m + n) time, and the checks can be done with index arithmetic instead of new strings.