Start learning free

LESSON 163 OF 348 · LOOPS - CHALLENGES

Longest Common Prefix of Two Strings in TypeScript: Index Loop

Practice Read the full explanation

Given two strings s1 and s2, return their longest common prefix

Example 1:

Input:  s1 = "hello", s2 = "help"
Output:  "hel"

Example 2:

Input:  s1 = "Andy", s2 = "Mircea"
Output:  ""

Example 3:

Input:  s1 = "AlgoCademy", s2 = "Algo"
Output:  "Algo"

STEP 1 OF 6
    Ctrl + Enter to check

    TYPESCRIPT · LOOPS - CHALLENGES

    Longest Common Prefix Of Two Strings in TypeScript, explained

    Problem overview

    The method longestCommonPrefix(s1, s2) receives two strings and returns the longest string that both of them start with. For "hello" and "help" the answer is "hel": the first three characters match, and then l meets p. For "Andy" and "Mircea" the first characters already differ, so the answer is the empty string. For "AlgoCademy" and "Algo" the answer is "Algo", because the shorter string is a prefix of the longer one.

    Approach: compare position by position

    A common prefix is a stretch of matching characters starting at index 0. So compare s1[0] with s2[0], then s1[1] with s2[1], and so on. As long as the characters match, add them to the answer. At the first mismatch, stop: after a mismatch nothing further can belong to the prefix, even if later characters happen to match again.

    There is a second reason to stop, which is running out of characters. The prefix can't be longer than the shorter string, so the loop should go up to Math.min(s1.length, s2.length) and no further. If it went past the end of the shorter string, the lookup would give undefined rather than a character.

    A slower idea would try every candidate length from the longest down to 0, slicing s1 and testing whether s2 starts with the slice. Each test costs time proportional to the candidate's length, so the total grows with the square of the length. One scan from the left finds the answer in a single pass, because it never looks at a position twice.

    Step by step

    1. Compute the limit n as the smaller of the two lengths with Math.min. In TypeScript length is a property, so there are no parentheses after it.
    2. Create commonPrefix as an empty string with let, because you will reassign it as it grows.
    3. Loop with i from 0 while i < n, so the index is always valid in both strings.
    4. Break on a mismatch. If s1[i] differs from s2[i], leave the loop immediately.
    5. Otherwise append s1[i] to commonPrefix with +=. The characters are equal at this point, so taking one from s1 is enough.
    6. Return commonPrefix after the loop. This line is reached both after a break and after the loop has checked all n positions.

    A worked trace

    Take s1 = "hello" and s2 = "help". The lengths are 5 and 4, so n is 4 and the valid indices are 0 to 3. At i = 0, h equals h and commonPrefix becomes "h". At i = 1 it becomes "he", and at i = 2 it becomes "hel". At i = 3 the characters are l and p, which differ, so the loop breaks and the function returns "hel".

    For "AlgoCademy" and "Algo" the limit is 4. All four positions match, the loop ends because i reached n, and the result is "Algo". No mismatch is needed to finish.

    The solution in TypeScript

    class Solution {
        longestCommonPrefix(s1: string, s2: string): string {
            let n: number = Math.min(s1.length, s2.length);
            let commonPrefix: string = "";
            for (let i = 0; i < n; i++) {
                if (s1[i] != s2[i]) {
                    break;
                }
                commonPrefix += s1[i];
            }
            return commonPrefix;
        }
    }

    A few language details apply here. Indexing a string with s1[i] gives a one-character string, and strings can be compared and joined with != and +=. Strings are immutable, so commonPrefix += s1[i] doesn't change the old string: it creates a new one and stores it in the variable. Between two strings, != and the stricter !== give the same answer, but !== is the usual habit in TypeScript.

    Indexes count UTF-16 code units, not visible characters. For text with emoji, one visible symbol can take two positions, so a prefix cut by this loop could split it. That doesn't affect ordinary letters, and the lesson's strings use them.

    Complexity

    In the worst case the loop runs min(m, k) times, where m and k are the two lengths, and every step does constant work, so the time is O(min(m, k)). The extra space is the result string, which can be as long as the shorter input, so it is O(min(m, k)) too, beyond the inputs themselves.

    Edge cases and common mistakes

    • An empty string. If either input is empty, n is 0, the loop doesn't run, and the result is "".
    • Identical strings. The loop checks every position and returns a copy of the string.
    • One string is a prefix of the other. The loop ends because i reaches n, not because of a mismatch, and still returns the correct prefix.
    • Using the longer length as the limit. This reads past the end of the shorter string, where s2[i] is undefined. The comparison then sees a mismatch by accident, which works only by luck.
    • Case matters. "Algo" and "algo" share no prefix, because A and a are different characters.
    • Using continue instead of break. That would skip a mismatching position but keep going, and later matching characters would be appended.

    Testing

    Try ("flower", "flow"), which gives "flow"; ("abc", "abd"), which gives "ab"; and ("", "abc"), which gives the empty string.

    Keep going with TypeScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free