Rabin Karp String Matching in DSA Python - 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 Rabin Karp method handle this search efficiently?
Analyze the time complexity of the following code snippet.
def rabin_karp(text, pattern):
n, m = len(text), len(pattern)
p_hash = hash(pattern)
for i in range(n - m + 1):
t_hash = hash(text[i:i+m])
if t_hash == p_hash and text[i:i+m] == pattern:
return i
return -1
This code tries to find the first place where the pattern appears in the text using hashing to speed up comparisons.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through the text to check each substring of pattern length.
- How many times: Approximately n - m + 1 times, where n is text length and m is pattern length.
- Secondary operation: Computing hash for each substring and comparing hashes.
As the text grows, the number of substring checks grows roughly in a straight line with the text size.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 checks |
| 100 | About 100 checks |
| 1000 | About 1000 checks |
Pattern observation: The work grows linearly with the text size, assuming pattern size is much smaller.
Time Complexity: O(n * m) on average, O(n * m) in worst case
This means on average, the search grows roughly with the product of text and pattern sizes, and in worst case it can be slower.
[X] Wrong: "Rabin Karp always runs in linear time no matter what."
[OK] Correct: Sometimes many hash collisions happen, causing extra checks that slow it down to quadratic time.
Understanding Rabin Karp helps you see how hashing can speed up searching and when it might slow down, a useful skill for many coding problems.
"What if we used a rolling hash to avoid recomputing the hash from scratch each time? How would the time complexity change?"
Practice
Rabin Karp String Matching algorithm?Solution
Step 1: Understand Rabin Karp's approach
The algorithm uses a hash function to convert the pattern and text substrings into numbers.Step 2: Use hashing for efficient matching
By comparing hash values instead of characters, it quickly finds potential matches.Final Answer:
It uses hashing to find pattern matches efficiently. -> Option AQuick Check:
Hashing = Efficient matching [OK]
- Thinking it compares characters directly without hashing
- Confusing it with sorting-based algorithms
- Assuming it uses recursion
Solution
Step 1: Recall rolling hash formula
Rolling hash removes the old char's contribution and adds the new char's value.Step 2: Apply formula correctly
It subtracts old_char * base^(m-1), multiplies by base, then adds new_char.Final Answer:
new_hash = (old_hash - old_char * base^(m-1)) * base + new_char -> Option CQuick Check:
Rolling hash formula = new_hash = (old_hash - old_char * base^(m-1)) * base + new_char [OK]
- Adding old_char instead of subtracting
- Dividing instead of multiplying by base
- Ignoring power of base for old_char
def rabin_karp(text, pattern):
base = 256
prime = 101
m = len(pattern)
n = len(text)
pattern_hash = 0
text_hash = 0
h = 1
for i in range(m-1):
h = (h * base) % prime
for i in range(m):
pattern_hash = (base * pattern_hash + ord(pattern[i])) % prime
text_hash = (base * text_hash + ord(text[i])) % prime
for i in range(n - m + 1):
if pattern_hash == text_hash:
if text[i:i+m] == pattern:
return i
if i < n - m:
text_hash = (base * (text_hash - ord(text[i]) * h) + ord(text[i + m])) % prime
if text_hash < 0:
text_hash += prime
return -1
print(rabin_karp('ababc', 'abc'))Solution
Step 1: Calculate pattern and initial text hash
Pattern 'abc' length 3, initial text substring 'aba'. Hashes differ, so move forward.Step 2: Slide over text and compare hashes
At index 1, substring 'bab' hash differs. At index 2, substring 'abc' hash matches pattern hash and strings match.Final Answer:
2 -> Option DQuick Check:
Pattern found at index 2 [OK]
- Returning first hash match without substring check
- Confusing index positions
- Ignoring negative hash adjustment
text_hash = (base * (text_hash - ord(text[i]) * h) + ord(text[i + m])) % prime
if text_hash < 0:
text_hash = text_hash - primeSolution
Step 1: Understand negative hash correction
If hash is negative after modulo, add prime to make it positive.Step 2: Identify incorrect operation
Code subtracts prime instead of adding it, causing wrong hash values.Final Answer:
The negative hash correction should add prime, not subtract. -> Option AQuick Check:
Negative hash fix = add prime [OK]
- Subtracting prime instead of adding
- Ignoring negative hash values
- Misplacing modulo operation
Solution
Step 1: Understand multiple pattern search challenge
Running Rabin Karp separately for each pattern is inefficient for many patterns.Step 2: Use combined hashing approach
Hash all patterns and store in a set. Then check each text substring's hash against this set for quick matches.Final Answer:
Use a combined hash set of all patterns and check text substrings against it. -> Option BQuick Check:
Combined hash set = efficient multi-pattern search [OK]
- Running separate searches for each pattern
- Sorting patterns instead of hashing
- Using recursion unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
