Longest Common Prefix in DSA Go - Time & Space Complexity
We want to know how the time to find the longest common prefix grows as we add more words or longer words.
How does the work increase when the input list or word length grows?
Analyze the time complexity of the following code snippet.
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
prefix := strs[0]
for i := 1; i < len(strs); i++ {
for len(prefix) > 0 && !strings.HasPrefix(strs[i], prefix) {
prefix = prefix[:len(prefix)-1]
}
}
return prefix
}
This code finds the longest common prefix among a list of strings by comparing prefixes and shortening them until all strings match.
- Primary operation: Nested loops where the outer loop goes through each string and the inner loop shortens the prefix until it matches.
- How many times: Outer loop runs n-1 times (n = number of strings), inner loop runs up to length of prefix each time.
As the number of strings (n) or the length of the prefix (m) grows, the work increases roughly by multiplying these two.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 strings, prefix length 5 | About 50 checks |
| 100 strings, prefix length 10 | About 1000 checks |
| 1000 strings, prefix length 20 | About 20,000 checks |
Pattern observation: The operations grow roughly by multiplying the number of strings by the prefix length.
Time Complexity: O(n * m)
This means the time grows proportionally with the number of strings and the length of the prefix we check.
[X] Wrong: "The time depends only on the number of strings, not their length."
[OK] Correct: The prefix length matters because we compare characters one by one, so longer prefixes mean more work.
Understanding this helps you explain how your solution scales with input size, a key skill interviewers look for.
"What if we sorted the strings first and only compared the first and last strings? How would the time complexity change?"
Practice
Solution
Step 1: Understand the prefix concept
A prefix is a substring starting at the beginning of a string.Step 2: Define longest common prefix
The longest common prefix is the longest substring starting at the beginning that all strings share.Final Answer:
The longest starting substring common to all strings -> Option AQuick Check:
Prefix means start of string = longest common start substring [OK]
- Confusing prefix with substring anywhere
- Thinking about suffix instead of prefix
- Assuming shortest substring is the answer
strs with values "flower", "flow", "flight"?Solution
Step 1: Identify correct slice initialization syntax
In Go, slices are initialized with []type{values} syntax.Step 2: Check each option
strs := []string{"flower", "flow", "flight"} uses []string with curly braces correctly. strs := [3]string{"flower", "flow", "flight"} uses array syntax but is valid but fixed size, not slice. var strs = {"flower", "flow", "flight"} uses invalid braces. strs := string{"flower", "flow", "flight"} uses wrong type syntax.Final Answer:
strs := []string{"flower", "flow", "flight"} -> Option CQuick Check:
Slice syntax = []type{values} [OK]
- Using array syntax when slice is needed
- Missing type brackets []
- Using curly braces without type
["dog", "racecar", "car"], what should the longest common prefix function return and why?Solution
Step 1: Compare prefixes of all strings
"dog" starts with 'd', "racecar" with 'r', "car" with 'c'. No common starting character exists.Step 2: Determine longest common prefix
Since no common starting substring exists, the longest common prefix is empty string "".Final Answer:
"" because no common prefix exists -> Option BQuick Check:
No common start means empty prefix [OK]
- Assuming shortest string is prefix
- Picking first string's first letter
- Ignoring all strings must share prefix
package main
import "fmt"
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
prefix := strs[0]
for _, s := range strs[1:] {
for len(prefix) > 0 && len(s) >= len(prefix) && s[:len(prefix)] != prefix {
prefix = prefix[:len(prefix)-1]
}
}
return prefix
}
func main() {
strs := []string{"inter", "internet", "internal"}
fmt.Println(longestCommonPrefix(strs))
}Solution
Step 1: Initialize prefix and compare with each string
Prefix starts as "inter". Compare with "internet": len(s)=8 >=5 and "internet"[:5] == "inter", so no reduction.Step 2: Compare prefix "inter" with "internal"
len(s)=8 >=5 and "internal"[:5] == "inter", so prefix remains "inter".Final Answer:
inter -> Option DQuick Check:
Common start of all strings = "inter" [OK]
- Not shrinking prefix correctly
- Comparing prefix with wrong substring
- Returning initial prefix without checks
func longestCommonPrefix(strs []string) string {
if len(strs) == 0 {
return ""
}
prefix := strs[0]
for _, s := range strs[1:] {
for len(prefix) > 0 && s[:len(prefix)] != prefix {
prefix = prefix[:len(prefix)-1]
}
}
return prefix
}Solution
Step 1: Analyze substring slicing in loop
The code slices s[:len(prefix)] without checking if s is long enough, causing runtime panic if s is shorter than prefix.Step 2: Fix by adding length check
Adding condition len(s) >= len(prefix) before slicing prevents out-of-range error.Final Answer:
Add check that len(s) >= len(prefix) before s[:len(prefix)] -> Option AQuick Check:
Prevent slice out-of-range by length check [OK]
- Ignoring string length before slicing
- Changing prefix initialization unnecessarily
- Skipping loop over all strings
Ready to prove it?
Pass the test and this pattern moves unknown
