LeetCode #14 — Easy

Longest Common
Prefix

A complete visual walkthrough of scanning strings character by character to find their shared beginning.

Solve on LeetCode
The Problem

Problem Statement

Write a function to find the longest common prefix string amongst an array of strings.

If there is no common prefix, return an empty string "".

Example 1:

Input: strs = ["flower","flow","flight"]
Output: "fl"

Example 2:

Input: strs = ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.

Constraints:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i] consists of only lowercase English letters if it is non-empty.

Roadmap

  1. Brute Force — Vertical Scanning
  2. The Core Insight
  3. Algorithm Walkthrough
  4. Edge Cases
  5. Full Annotated Code
  6. Interactive Demo
  7. Complexity Analysis
Step 01

Brute Force — Vertical Scanning

The most intuitive approach: scan column by column. Stack all the strings vertically and move a pointer from left to right, checking if every string has the same character at that position.

Vertical Scanning Visualized

Given ["flower", "flow", "flight"], we stack the strings and scan each column:

column
0
1
2
3
4
5
flower
f
l
o
w
e
r
flow
f
l
o
w
flight
f
l
i
g
h
t
All match
First mismatch (stop here)
Not checked
Column 0: all "f" -- Column 1: all "l" -- Column 2: "o" vs "i" MISMATCH
Result: "fl"

At column 2, "flower" and "flow" have 'o' but "flight" has 'i'. The characters don't all match, so we stop. Everything before that column is the longest common prefix.

Step 02

The Core Insight

There are a few key observations that make this problem clean to solve:

Three Key Observations

Observation 1
The common prefix can never be longer than the shortest string. If one string has 3 characters, the prefix is at most 3 characters.
Observation 2
At each column position, every string must have the same character. One mismatch anywhere in the column means we stop immediately.
Observation 3
We only need to compare against the first string. Pick strs[0] as the reference, then check if every other string matches it at each position.
💡

Alternative approach — sort first: If you sort the array lexicographically, the first and last strings will be the most different. You only need to compare those two to find the common prefix. Sorting costs O(S log n) though, so vertical scanning is usually better.

Why Sorting Works

After sorting ["flower", "flow", "flight"] lexicographically:

first
f
l
i
g
h
t
flow
f
l
o
w
last
f
l
o
w
e
r

The middle strings are irrelevant. If first and last share a prefix, all strings in between share it too (because of lexicographic ordering).

Step 03

Algorithm Walkthrough

Let's trace through the vertical scanning algorithm step by step with ["flower", "flow", "flight"].

Column 0 — Checking character 'f'

Take strs[0].charAt(0) = 'f' and compare against all other strings:

flower
f
l
o
w
e
r
flow
f
l
o
w
flight
f
l
i
g
h
t
All strings have 'f' at position 0. Continue.

Column 1 — Checking character 'l'

Take strs[0].charAt(1) = 'l' and compare:

flower
f
l
o
w
e
r
flow
f
l
o
w
flight
f
l
i
g
h
t
All strings have 'l' at position 1. Continue.

Column 2 — Checking character 'o'

Take strs[0].charAt(2) = 'o' and compare:

flower
f
l
o
w
e
r
flow
f
l
o
w
flight
f
l
i
g
h
t
"flight" has 'i' instead of 'o'. MISMATCH at position 2!
Return strs[0].substring(0, 2) = "fl"

Early termination: The moment we find a mismatch at position i, we immediately return. We don't need to check any more columns or any more strings in that column. This is what makes vertical scanning efficient in practice.

Step 04

Edge Cases

Every good solution handles the boundaries. Here are the cases to watch for:

Empty Array
strs = []
return ""
No strings at all. Guard clause catches this.
Null Input
strs = null
return ""
Defensive check at the top of the function.
Single String
strs = ["alone"]
return "alone"
Inner loop (j=1..n) never executes. The entire first string is returned.
Contains Empty String
strs = ["abc", "", "ab"]
return ""
At i=0, the empty string hits i == strs[j].length() immediately.
All Identical
strs = ["abc", "abc", "abc"]
return "abc"
No mismatch found. Loop ends naturally and returns strs[0].
Single Characters
strs = ["a", "a", "b"]
return ""
Mismatch at very first column. Returns substring(0, 0) = "".
💡

The length check is crucial: The condition i == strs[j].length() fires before we try to access strs[j].charAt(i), preventing an index out of bounds. This naturally handles strings shorter than the first one.

Step 05

Full Annotated Code

The vertical scanning approach in its entirety. Clean, simple, and handles all edge cases:

class Solution {
    public String longestCommonPrefix(String[] strs) {

        // Guard: empty or null input
        if (strs == null || strs.length == 0) return "";

        // Scan column by column, using strs[0] as reference
        for (int i = 0; i < strs[0].length(); i++) {

            // Character to match at column i
            char c = strs[0].charAt(i);

            // Check every other string at this column
            for (int j = 1; j < strs.length; j++) {

                // Two stop conditions:
                // 1. strs[j] is too short (ran out of characters)
                // 2. Character mismatch at position i
                if (i == strs[j].length() || strs[j].charAt(i) != c) {
                    return strs[0].substring(0, i);
                }
            }
        }

        // All columns matched — strs[0] itself is the prefix
        return strs[0];
    }
}
📝

Why use strs[0] as the reference? Any string could work, but using the first string is cleanest. The outer loop iterates over its characters, and the inner loop checks all other strings. If strs[0] happens to be longer than the actual prefix, the inner loop catches it early via the length or mismatch check.

Step 06

Interactive Demo

Enter comma-separated strings and step through the algorithm column by column. Watch the character grid light up as each position is scanned.

⚙ Vertical Scanner


Step 07

Complexity Analysis

Time
O(n × m)
Space
O(1)

Where n is the number of strings and m is the length of the shortest string. The outer loop runs at most m times (one per column), and the inner loop checks all n strings at each column. In the worst case (all strings identical), we examine every character once. In the best case, the first column already has a mismatch and we return immediately.

Approach Breakdown

VERTICAL SCAN
O(n × m) time
O(1) space

The outer loop scans up to m columns (length of the shortest string) and the inner loop checks all n strings at each column. Early termination at the first mismatch means it never revisits a character. Only an index variable and character reference are needed in memory.

SORT + COMPARE
O(S log n) time
O(S) space

Lexicographic sorting takes O(S log n) where S is the sum of all character lengths, since each string comparison costs up to O(m). After sorting, only the first and last strings need to be compared character by character. The sort itself requires O(S) auxiliary space for string copies.

BINARY SEARCH
O(n × m × log m)
O(1) space

Binary search on the prefix length performs O(log m) probes, and each probe verifies the candidate prefix across all n strings by comparing up to mid characters each, costing O(n × mid) per step. No extra data structures are needed, but the redundant re-checking makes it slower than vertical scanning.

🎯

Binary search on prefix length gives O(n × m × log m), which is worse. At each binary search step you still need to verify the candidate prefix across all n strings (O(n × mid) work), and you do O(log m) steps. Vertical scanning is already optimal -- it stops at the first mismatch and never revisits a character.

Coach Notes

Common Mistakes

Review these before coding to avoid predictable interview regressions.

Off-by-one on range boundaries

Wrong move: Loop endpoints miss first/last candidate.

Usually fails on: Fails on minimal arrays and exact-boundary answers.

Fix: Re-derive loops from inclusive/exclusive ranges before coding.