KMP Pattern Matching Algorithm in DSA Javascript - Time & Space Complexity
We want to understand how the KMP algorithm's running time changes as the text and pattern sizes grow.
Specifically, how fast can it find a pattern inside a text?
Analyze the time complexity of this KMP pattern matching code.
function kmpSearch(text, pattern) {
const lps = computeLPSArray(pattern);
let i = 0, j = 0;
while (i < text.length) {
if (pattern[j] === text[i]) {
i++; j++;
if (j === pattern.length) return i - j;
} else if (j !== 0) {
j = lps[j - 1];
} else {
i++;
}
}
return -1;
}
function computeLPSArray(pattern) {
const lps = Array(pattern.length).fill(0);
let length = 0, i = 1;
while (i < pattern.length) {
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 the first occurrence of a pattern inside a text using the KMP algorithm, which precomputes a helper array (LPS) to skip unnecessary checks.
Look at the loops and repeated steps:
- Primary operation: Comparing characters of text and pattern.
- How many times: Each character in text and pattern is visited at most twice during the search and LPS computation.
As the text length (n) and pattern length (m) grow, the number of operations grows roughly in a straight line.
| Input Size (n, m) | Approx. Operations |
|---|---|
| n=10, m=3 | About 20-30 comparisons |
| n=100, m=10 | About 200-300 comparisons |
| n=1000, m=50 | About 2000-3000 comparisons |
Pattern observation: The operations grow roughly proportional to the sum of text and pattern lengths, not their product.
Time Complexity: O(n + m)
This means the algorithm checks characters in the text and pattern only a few times, making it very efficient even for large inputs.
[X] Wrong: "KMP takes O(n * m) time because it compares every pattern character with every text character."
[OK] Correct: KMP smartly uses the LPS array to avoid rechecking characters, so it never goes back in the text, keeping the total comparisons linear.
Understanding KMP's time complexity shows you can analyze efficient algorithms that cleverly reduce repeated work, a key skill in coding interviews.
"What if the pattern was very long compared to the text? How would that affect the time complexity?"
Practice
Solution
Step 1: Understand the problem KMP solves
KMP is designed to find all occurrences of a pattern inside a text without rechecking characters unnecessarily.Step 2: Compare with other options
Sorting, reversing strings, and factorial calculation are unrelated to pattern searching.Final Answer:
To find occurrences of a pattern string within a text efficiently -> Option BQuick Check:
KMP = Pattern searching [OK]
- Confusing KMP with sorting algorithms
- Thinking KMP reverses strings
- Assuming KMP calculates factorials
Solution
Step 1: Understand prefix array initialization
The prefix array (lps) must be initialized with zeros to store lengths of longest prefix suffix.Step 2: Check each option
const lps = new Array(pattern.length).fill(0); correctly creates an array of the pattern's length filled with zeros. const lps = Array(pattern.length); creates an array but leaves elements undefined. const lps = []; lps.length = pattern.length; sets length but elements are undefined. const lps = new Array(pattern.length).fill(null); fills with null, which is incorrect.Final Answer:
const lps = new Array(pattern.length).fill(0); -> Option DQuick Check:
Prefix array = zeros [OK]
- Leaving prefix array elements undefined
- Filling prefix array with null instead of zero
- Not initializing prefix array length
function KMPSearch(pattern, text) {
const lps = computeLPSArray(pattern);
let i = 0, j = 0;
const result = [];
while (i < text.length) {
if (pattern[j] === text[i]) {
i++; j++;
if (j === pattern.length) {
result.push(i - j);
j = lps[j - 1];
}
} else if (j !== 0) {
j = lps[j - 1];
} else {
i++;
}
}
return result;
}
function computeLPSArray(pattern) {
const lps = new Array(pattern.length).fill(0);
let length = 0, i = 1;
while (i < pattern.length) {
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;
}
console.log(KMPSearch('ABABC', 'ABABABCABABCBC'));Solution
Step 1: Compute LPS array for pattern 'ABABC'
LPS array is [0, 0, 1, 2, 0]. This helps skip characters on mismatch.Step 2: Trace pattern matches in text 'ABABABCABABCBC'
Pattern matches start at index 2 and again at index 7 in the text.Final Answer:
[2, 7] -> Option CQuick Check:
Match indices = [2, 7] [OK]
- Incorrect LPS array calculation
- Off-by-one errors in indices
- Confusing pattern length with text length
function computeLPSArray(pattern) {
const lps = new Array(pattern.length).fill(0);
let length = 0;
let i = 0;
while (i < pattern.length) {
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
The prefix array computation starts from index 1 because index 0 always has lps value 0.Step 2: Identify impact of starting at i=0
Starting at i=0 causes comparing pattern[0] with pattern[0] unnecessarily and overwrites lps[0], which should remain 0.Final Answer:
The loop should start with i = 1, not i = 0 -> Option AQuick Check:
Start loop at 1 for prefix array [OK]
- Starting loop at 0
- Initializing length incorrectly
- Filling lps with wrong values
Solution
Step 1: Understand overlapping matches
Overlapping matches require continuing search from the longest proper prefix which is also suffix, not restarting.Step 2: Apply correct jump after match
Setting j = lps[j - 1] after a match allows the algorithm to find overlapping occurrences without missing any.Final Answer:
After a match, set j = lps[j - 1] instead of resetting j to 0 -> Option AQuick Check:
Use lps jump to count overlaps [OK]
- Resetting j to 0 after match
- Skipping characters by incrementing i too much
- Not handling overlaps correctly
Ready to prove it?
Pass the test and this pattern moves unknown
