DEV Community

Cover image for Typescript Coding Chronicles: Greatest Common Divisor of Strings
Zamora
Zamora

Posted on

Typescript Coding Chronicles: Greatest Common Divisor of Strings

Problem Statement:

For two strings s and t, we say "t divides s" if and only if s = t + t + t + ... + t + t (i.e., t is concatenated with itself one 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: ""

Constraints:

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

Understanding the Problem:

To solve this problem, we need to find the largest string that, when repeated, can form both str1 and str2. This problem is akin to finding the greatest common divisor (GCD) of two numbers, but instead, we are dealing with strings.

Initial Thought Process:

We need to determine if the two strings have a common pattern that can repeatedly form both strings. If str1 + str2 is equal to str2 + str1, then there exists a common divisor string. The length of this common string would be the GCD of the lengths of str1 and str2.

Basic Solution:

The basic approach involves concatenating the strings and checking for the condition str1 + str2 === str2 + str1. If this holds true, the solution would be the substring of str1 up to the length of the GCD of their lengths.

Code:

function gcdOfStringsBasic(str1: string, str2: string): string {
    // Helper function to find the greatest common divisor of two numbers
    function gcd(a: number, b: number): number {
        if (b === 0) {
            return a;
        }
        return gcd(b, a % b);
    }

    // Check if str1 + str2 is the same as str2 + str1
    if (str1 + str2 !== str2 + str1) {
        return "";
    }

    // Find the greatest common divisor of the lengths of str1 and str2
    let gcdLength = gcd(str1.length, str2.length);

    // Return the substring of str1 or str2 from 0 to gcdLength
    return str1.substring(0, gcdLength);
}
Enter fullscreen mode Exit fullscreen mode

Time Complexity Analysis:

  • Time Complexity: O(n + m), where n is the length of str1 and m is the length of str2. The concatenation check takes O(n + m) time, and the GCD computation takes O(log(min(n, m))).
  • Space Complexity: O(n + m) for the concatenated strings and O(1) for the GCD computation.

Limitations:

The basic solution is efficient given the problem constraints. It leverages string concatenation and GCD computation to achieve the desired result.

Optimized Solution:

The basic solution is already quite optimal, but we can ensure that the code is as efficient and clean as possible. We will reuse the GCD computation function and include a more streamlined approach to check for the common divisor.

Code:

function gcdOfStringsOptimized(str1: string, str2: string): string {
    // Helper function to find the greatest common divisor of two numbers
    function gcd(a: number, b: number): number {
        while (b !== 0) {
            [a, b] = [b, a % b];
        }
        return a;
    }

    // Check if str1 + str2 is the same as str2 + str1
    if (str1 + str2 !== str2 + str1) {
        return "";
    }

    // Find the greatest common divisor of the lengths of str1 and str2
    let gcdLength = gcd(str1.length, str2.length);

    // Return the substring of str1 or str2 from 0 to gcdLength
    return str1.substring(0, gcdLength);
}
Enter fullscreen mode Exit fullscreen mode

Time Complexity Analysis:

  • Time Complexity: O(n + m), where n is the length of str1 and m is the length of str2. The concatenation check takes O(n + m) time, and the GCD computation takes O(log(min(n, m))).
  • Space Complexity: O(1) for the GCD computation, as the concatenation check does not store additional strings.

Improvements Over Basic Solution:

  • The optimized solution uses an iterative approach for the GCD function, which can be more efficient than the recursive approach in some environments.
  • It also avoids creating new strings unnecessarily, making it slightly more space efficient.

Edge Cases and Testing:

Edge Cases:

  1. str1 is a multiple of str2.
  2. str2 is a multiple of str1.
  3. str1 and str2 have no common divisor.
  4. str1 or str2 is empty.

Test Cases:

console.log(gcdOfStringsBasic("ABCABC", "ABC")); // "ABC"
console.log(gcdOfStringsBasic("ABABAB", "ABAB")); // "AB"
console.log(gcdOfStringsBasic("LEET", "CODE")); // ""
console.log(gcdOfStringsBasic("ABCDEF", "ABC")); // ""
console.log(gcdOfStringsBasic("AAAAAA", "AA")); // "AA"
console.log(gcdOfStringsBasic("AA", "A")); // "A"

console.log(gcdOfStringsOptimized("ABCABC", "ABC")); // "ABC"
console.log(gcdOfStringsOptimized("ABABAB", "ABAB")); // "AB"
console.log(gcdOfStringsOptimized("LEET", "CODE")); // ""
console.log(gcdOfStringsOptimized("ABCDEF", "ABC")); // ""
console.log(gcdOfStringsOptimized("AAAAAA", "AA")); // "AA"
console.log(gcdOfStringsOptimized("AA", "A")); // "A"
Enter fullscreen mode Exit fullscreen mode

General Problem-Solving Strategies:

  1. Understand the Problem: Carefully read the problem statement to understand the requirements and constraints.
  2. Break Down the Problem: Identify key operations such as checking concatenations and computing GCD of lengths.
  3. Use Helper Functions: Implement helper functions like gcd to simplify the main solution.
  4. Consider Edge Cases: Think about different scenarios that might affect the solution, such as when the strings are not divisible or one string is empty.
  5. Start Simple and Optimize: Begin with a basic solution that works, even if it's not the most efficient. This helps to ensure you understand the problem. Then, look for ways to optimize it.
  6. Optimize for Readability: Ensure the solution is clean and easy to understand while maintaining efficiency.
  7. Test Thoroughly: Test your solution with various cases, including edge cases. Ensure that the solution handles all possible inputs correctly.

Identifying Similar Problems:

  1. String Repetition and Pattern Matching:

    • Problems where you need to find repeating patterns within strings.
    • Example: Finding the smallest repeating unit in a string.
  2. Greatest Common Divisor (GCD):

    • Problems involving GCD computations in different contexts.
    • Example: Finding the GCD of two numbers or the GCD of lengths of multiple strings.
  3. String Concatenation and Validation:

    • Problems where you need to validate if one string can be formed by concatenating another string multiple times.
    • Example: Checking if a string is a repeated substring of another string.
  4. Subsequence and Substring Problems:

    • Problems involving finding common subsequences or substrings between multiple strings.
    • Example: Longest common subsequence or longest common substring problems.

Conclusion:

  • The problem of finding the greatest common divisor of two strings can be efficiently solved by leveraging string concatenation and GCD computations.
  • Understanding the problem and breaking it down into manageable parts is crucial.
  • Testing with various edge cases ensures robustness.
  • Recognizing patterns in problems can help apply similar solutions to other challenges.

By practicing such problems and strategies, you can improve your problem-solving skills and be better prepared for various coding challenges.

Top comments (0)