KMP Pattern Matching Algorithm in DSA Go - Time & Space Complexity
We want to understand how fast the KMP algorithm finds a pattern inside a text.
Specifically, how the work grows as the text and pattern get longer.
Analyze the time complexity of the following KMP pattern matching code.
func KMPSearch(text, pattern string) []int {
lps := computeLPSArray(pattern)
var result []int
i, j := 0, 0
for i < len(text) {
if text[i] == pattern[j] {
i++
j++
if j == len(pattern) {
result = append(result, i-j)
j = lps[j-1]
}
} else if j != 0 {
j = lps[j-1]
} else {
i++
}
}
return result
}
func computeLPSArray(pattern string) []int {
lps := make([]int, len(pattern))
length := 0
i := 1
for i < len(pattern) {
if pattern[i] == pattern[length] {
length++
lps[i] = length
i++
} else if length != 0 {
length = lps[length-1]
} else {
lps[i] = 0
i++
}
}
return lps
}
This code finds all occurrences of a pattern inside a text efficiently using the KMP algorithm.
Look at the loops and repeated steps in the code.
- Primary operation: The main loop scans the text once, and the LPS computation scans the pattern once.
- How many times: Each character in text and pattern is visited at most twice during the process.
As the text length (n) and pattern length (m) grow, the work grows roughly in a straight line.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 (text), 3 (pattern) | About 13 steps |
| 100 (text), 10 (pattern) | About 110 steps |
| 1000 (text), 50 (pattern) | About 1050 steps |
Pattern observation: The total steps grow roughly as the sum of text and pattern lengths, not their product.
Time Complexity: O(n + m)
This means the algorithm checks each character in the text and pattern only a few times, making it very efficient.
[X] Wrong: "KMP takes O(n * m) time because it compares every pattern character with every text character."
[OK] Correct: KMP uses the LPS array to skip unnecessary comparisons, so it never rechecks characters unnecessarily, keeping time linear.
Knowing KMP's time complexity shows you understand efficient string searching, a useful skill for many coding challenges and real-world text processing.
"What if we used a naive search instead of KMP? How would the time complexity change?"
Practice
Solution
Step 1: Understand KMP's goal
KMP is designed to find pattern matches in text efficiently by avoiding repeated comparisons.Step 2: Compare options with KMP's function
Only To efficiently find occurrences of a pattern in a text without rechecking characters describes this efficient search without rechecking characters.Final Answer:
To efficiently find occurrences of a pattern in a text without rechecking characters -> Option AQuick Check:
KMP purpose = efficient pattern search [OK]
- Thinking KMP sorts or modifies the text
- Confusing KMP with simple substring search
- Assuming KMP counts characters instead of searching
Solution
Step 1: Identify correct Go syntax for integer slice
In Go, make([]int, size) creates an integer slice of given size.Step 2: Check options for correct slice creation
lps := make([]int, len(pattern)) correctly creates an int slice for lps. Others use wrong types or syntax.Final Answer:
lps := make([]int, len(pattern)) -> Option BQuick Check:
Go slice for lps = make([]int, len(pattern)) [OK]
- Using wrong slice type like []string or []bool
- Using new(int) which creates a pointer, not slice
- Incorrect slice initialization syntax
package main
import "fmt"
func computeLPS(pattern string) []int {
lps := make([]int, len(pattern))
length := 0
i := 1
for i < len(pattern) {
if pattern[i] == pattern[length] {
length++
lps[i] = length
i++
} else {
if length != 0 {
length = lps[length-1]
} else {
lps[i] = 0
i++
}
}
}
return lps
}
func main() {
pattern := "ABABC"
lps := computeLPS(pattern)
fmt.Println(lps)
}Solution
Step 1: Compute LPS array for pattern "ABABC"
Check characters stepwise: - i=1: 'B' != 'A' => lps[1]=0 - i=2: 'A' == 'A' => length=1, lps[2]=1 - i=3: 'B' == 'B' => length=2, lps[3]=2 - i=4: 'C' != 'A' => length=lps[1]=0, lps[4]=0Step 2: Final LPS array is [0, 0, 1, 2, 0]
This matches [0 0 1 2 0] exactly.Final Answer:
[0 0 1 2 0] -> Option DQuick Check:
LPS for "ABABC" = [0 0 1 2 0] [OK]
- Confusing LPS values with pattern indices
- Not resetting length correctly on mismatch
- Assuming all zeros or increasing sequence
func computeLPS(pattern string) []int {
lps := make([]int, len(pattern))
length := 0
i := 0
for i < len(pattern) {
if pattern[i] == pattern[length] {
length++
lps[i] = length
i++
} else {
if length != 0 {
length = lps[length-1]
} else {
lps[i] = 0
i++
}
}
}
return lps
}Solution
Step 1: Check loop initialization for LPS computation
In KMP, i starts from 1 because lps[0] is always 0 and no comparison needed at index 0.Step 2: Identify incorrect i initialization
Here i starts at 0, causing incorrect comparisons and possible infinite loop.Final Answer:
The loop should start with i = 1, not 0 -> Option CQuick Check:
Start i=1 for LPS loop [OK]
- Starting loop at 0 causing wrong LPS values
- Initializing length incorrectly
- Wrong return type or array type
Solution
Step 1: Understand the pattern and text
The pattern "ABABCABAB" appears in the text at indices 10 and 12 (0-based indexing), overlapping occurrences.Step 2: Count occurrences using KMP logic
KMP finds two matches without rechecking characters, so total occurrences = 2.Final Answer:
2 -> Option AQuick Check:
Pattern occurs twice in text [OK]
- Counting overlapping matches incorrectly
- Overcounting occurrences
- Assuming zero matches due to complexity
Ready to prove it?
Pass the test and this pattern moves unknown
