String Pattern Matching Naive in DSA Javascript - Time & Space Complexity
We want to understand how the time needed to find a pattern in a text grows as the text and pattern get bigger.
How does the number of checks change when the input size increases?
Analyze the time complexity of the following code snippet.
function naivePatternSearch(text, pattern) {
const n = text.length;
const m = pattern.length;
for (let i = 0; i <= n - m; i++) {
let j = 0;
while (j < m && text[i + j] === pattern[j]) {
j++;
}
if (j === m) return i; // pattern found
}
return -1; // pattern not found
}
This code checks every possible position in the text to see if the pattern matches starting there.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The nested loops where the outer loop moves through the text and the inner loop compares characters of the pattern to the text.
- How many times: The outer loop runs about n - m + 1 times, and for each, the inner loop can run up to m times in the worst case.
As the text and pattern get longer, the number of character comparisons grows roughly by multiplying their lengths.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 (text), 3 (pattern) | About 8 * 3 = 24 comparisons |
| 100 (text), 5 (pattern) | About 96 * 5 = 480 comparisons |
| 1000 (text), 10 (pattern) | About 991 * 10 = 9,910 comparisons |
Pattern observation: The work grows roughly like the product of text length and pattern length.
Time Complexity: O(n * m)
This means the time needed grows proportionally to the length of the text times the length of the pattern.
[X] Wrong: "The pattern search always takes time proportional only to the text length (O(n))."
[OK] Correct: Because for each position in the text, the algorithm may check multiple characters of the pattern, so the pattern length also affects the time.
Understanding this basic search helps build intuition for more efficient algorithms and shows you can analyze nested loops clearly.
"What if we used a more advanced algorithm like KMP? How would the time complexity change compared to this naive approach?"
Practice
Solution
Step 1: Understand naive pattern matching
The naive algorithm tries to match the pattern starting at every position in the text.Step 2: Compare with other methods
Other methods like hashing or trees are not part of the naive approach.Final Answer:
It checks every possible position in the text to find the pattern. -> Option AQuick Check:
Naive = Check all positions [OK]
- Confusing naive with hashing or advanced algorithms
- Thinking naive sorts the text
- Assuming naive uses data structures like trees
for (___; i <= text.length - pattern.length; i++)Solution
Step 1: Identify loop initialization
The loop variable must start at 0 to check from the beginning of the text.Step 2: Choose correct declaration
Using 'let' is correct for block scope and allows incrementing i.Final Answer:
let i = 0 -> Option CQuick Check:
Loop start = let i = 0 [OK]
- Using 'const' which cannot be incremented
- Starting loop at 1 instead of 0
- Not declaring variable with let or var
function naiveSearch(text, pattern) {
let count = 0;
for (let i = 0; i <= text.length - pattern.length; i++) {
let j;
for (j = 0; j < pattern.length; j++) {
if (text[i + j] !== pattern[j]) break;
}
if (j === pattern.length) count++;
}
return count;
}
console.log(naiveSearch('abababa', 'aba'));Solution
Step 1: Check all pattern matches in text
Positions checked: 0,1,2,3,4. Matches at 0 ('aba'), 2 ('aba'), and 4 ('aba').Step 2: Count total matches
There are 3 matches of 'aba' in 'abababa'.Final Answer:
3 -> Option AQuick Check:
Count matches = 3 [OK]
- Missing overlapping matches
- Counting only non-overlapping occurrences
- Off-by-one errors in loop limits
function search(text, pattern) {
for (let i = 0; i < text.length; i++) {
let j = 0;
while (j < pattern.length && text[i + j] === pattern[j]) {
j++;
}
if (j === pattern.length) return i;
}
return -1;
}Solution
Step 1: Analyze loop range
The outer loop runs till i < text.length, which can cause out-of-bound access when i + j exceeds text length.Step 2: Correct loop condition
It should be i <= text.length - pattern.length to avoid overflow.Final Answer:
Loop condition should be i <= text.length - pattern.length -> Option BQuick Check:
Loop limit fix = i <= text.length - pattern.length [OK]
- Ignoring index overflow causing runtime errors
- Misplacing return statements
- Wrong logical operators in conditions
Solution
Step 1: Understand overlapping vs non-overlapping
Naive checks every position, counting overlapping matches. To avoid overlap, skip ahead after a match.Step 2: Modify loop increment
When a match is found, increase the index by pattern length to jump past the matched substring.Final Answer:
After finding a match, increment the outer loop index by pattern length instead of 1 -> Option DQuick Check:
Skip matched length to avoid overlap [OK]
- Trying to sort text which doesn't help
- Using hashing which is unrelated here
- Recursion adds complexity without solving overlap
Ready to prove it?
Pass the test and this pattern moves unknown
