KMP Pattern Matching Algorithm in DSA Java - Time & Space Complexity
We want to understand how the time taken by the KMP algorithm changes as the size of the text and pattern grow.
Specifically, how fast can it find a pattern inside a larger text?
Analyze the time complexity of the following KMP code snippet.
public void KMPSearch(String pat, String txt) {
int M = pat.length();
int N = txt.length();
int[] lps = new int[M];
computeLPSArray(pat, M, lps);
int i = 0, j = 0;
while (i < N) {
if (pat.charAt(j) == txt.charAt(i)) {
i++; j++;
}
if (j == M) {
j = lps[j - 1];
} else if (i < N && pat.charAt(j) != txt.charAt(i)) {
if (j != 0) j = lps[j - 1];
else i++;
}
}
}
This code searches for a pattern inside a text using the KMP algorithm, which uses a precomputed array to skip unnecessary checks.
Look at the loops and repeated steps:
- Primary operation: The while loop that scans through the text once.
- How many times: The text is scanned once, and the pattern is scanned partially using the lps array to avoid repeats.
- The computeLPSArray function also loops through the pattern once to build the lps array.
The algorithm processes each character in the text and pattern at most a few times.
| Input Size (n) | Approx. Operations |
|---|---|
| Text length = 10, Pattern length = 3 | About 13 operations |
| Text length = 100, Pattern length = 10 | About 110 operations |
| Text length = 1000, Pattern length = 50 | About 1050 operations |
Pattern observation: The operations grow roughly in a straight line with the size of text plus pattern.
Time Complexity: O(n + m)
This means the algorithm checks each character in the text and pattern only once, making it very efficient.
[X] Wrong: "KMP is slower because it looks back and repeats work."
[OK] Correct: KMP uses the lps array to avoid repeating checks, so it never re-examines characters unnecessarily, keeping the time linear.
Understanding KMP's time complexity shows you can analyze efficient algorithms that smartly avoid repeated work, a key skill in coding interviews.
"What if we removed the lps array and did a simple naive search? How would the time complexity change?"
Practice
Solution
Step 1: Understand KMP's goal
KMP algorithm is designed to search for a pattern inside a larger text efficiently.Step 2: Compare with other options
Sorting, reversing, or counting vowels are unrelated to pattern searching.Final Answer:
To efficiently find occurrences of a pattern within a text -> Option DQuick Check:
KMP = Pattern Searching [OK]
- Confusing KMP with sorting algorithms
- Thinking KMP reverses strings
- Assuming KMP counts characters
Solution
Step 1: Check array declaration syntax
In Java, arrays are declared with type[], e.g., int[] lps.Step 2: Check array size correctness
Prefix array size equals pattern length, so new int[pattern.length()] is correct.Final Answer:
int[] lps = new int[pattern.length()]; -> Option AQuick Check:
Correct Java array init = int[] lps = new int[pattern.length()]; [OK]
- Using incorrect array size (too big or too small)
- Wrong syntax like int lps instead of int[] lps
- Adding unnecessary +1 or -1 to length
String text = "ABABABCABABC"; String pattern = "ABABC"; List<Integer> result = KMPSearch(pattern, text); System.out.println(result);Assume KMPSearch returns a list of starting indices where pattern is found.
Solution
Step 1: Identify pattern occurrences in text
Check text "ABABABCABABC" for "ABABC" starting indices: - At index 0: substring "ABABA" does not match fully - At index 2: substring "ABABC" matches fully - At index 5: substring "CABAB" does not match - At index 6: substring "ABABC" matches fully Actually, the pattern "ABABC" occurs at indices 2 and 7, but index 7 is out of range for the second match. Re-examining carefully: - At index 0: substring "ABABA" partial - At index 5: substring "CABAB" no - At index 6: substring "ABABC" matches - At index 7: substring "BABC" incomplete So matches at indices 2 and 6.Step 2: Confirm no other matches
Other indices do not match the full pattern exactly.Final Answer:
[2, 6] -> Option BQuick Check:
Pattern found at indices 2 and 6
- Off-by-one errors in indexing
- Confusing partial matches as full matches
- Assuming matches start at 0 or 1 incorrectly
int len = 0;
int i = 1;
while (i < pattern.length()) {
if (pattern.charAt(i) == pattern.charAt(len)) {
len++;
lps[i] = len;
i++;
} else {
if (len != 0) {
len = lps[len - 1];
} else {
lps[i] = 0;
i++;
}
}
}
What is the bug in this code?Solution
Step 1: Analyze lps computation logic
This code follows the standard KMP prefix array logic: - Increment len and assign lps[i] when chars match - Reset len using lps[len-1] when mismatch and len != 0 - Assign 0 and increment i when len == 0Step 2: Verify no missing steps
Initialization of lps array is assumed done before; loop logic is correct.Final Answer:
No bug; code correctly computes lps array -> Option CQuick Check:
Standard KMP lps logic = No bug; code correctly computes lps array [OK]
- Thinking i must increment before lps assignment
- Resetting len incorrectly to 0 instead of lps[len-1]
- Forgetting to initialize lps array before loop
Solution
Step 1: Search for pattern occurrences in text
Check text "AABAACAABAABAABA" for pattern "AABAACAABAA": - At index 0: substring matches pattern fully - At index 7: substring "AABAACAABAA" matches fully - Other indices do not match fullyStep 2: Confirm matches
Two full matches found at indices 0 and 7.Final Answer:
2 -> Option AQuick Check:
Pattern appears twice fully [OK]
- Counting partial matches as full matches
- Missing the first match at index 0
- Assuming overlapping partial matches count
Ready to prove it?
Pass the test and this pattern moves unknown
