The Rabin-Karp Algorithm for finding a pattern within a piece of text with complexity O(nm), most efficient when it is used with multiple patterns as it is able to check if any of a set of patterns match a section of text in o(1) given the precomputed hashes. This will be the s
(pattern: str, text: str)
| 5 | |
| 6 | |
| 7 | def rabin_karp(pattern: str, text: str) -> bool: |
| 8 | """ |
| 9 | The Rabin-Karp Algorithm for finding a pattern within a piece of text |
| 10 | with complexity O(nm), most efficient when it is used with multiple patterns |
| 11 | as it is able to check if any of a set of patterns match a section of text in o(1) |
| 12 | given the precomputed hashes. |
| 13 | |
| 14 | This will be the simple version which only assumes one pattern is being searched |
| 15 | for but it's not hard to modify |
| 16 | |
| 17 | 1) Calculate pattern hash |
| 18 | |
| 19 | 2) Step through the text one character at a time passing a window with the same |
| 20 | length as the pattern |
| 21 | calculating the hash of the text within the window compare it with the hash |
| 22 | of the pattern. Only testing equality if the hashes match |
| 23 | """ |
| 24 | p_len = len(pattern) |
| 25 | t_len = len(text) |
| 26 | if p_len > t_len: |
| 27 | return False |
| 28 | |
| 29 | p_hash = 0 |
| 30 | text_hash = 0 |
| 31 | modulus_power = 1 |
| 32 | |
| 33 | # Calculating the hash of pattern and substring of text |
| 34 | for i in range(p_len): |
| 35 | p_hash = (ord(pattern[i]) + p_hash * alphabet_size) % modulus |
| 36 | text_hash = (ord(text[i]) + text_hash * alphabet_size) % modulus |
| 37 | if i == p_len - 1: |
| 38 | continue |
| 39 | modulus_power = (modulus_power * alphabet_size) % modulus |
| 40 | |
| 41 | for i in range(t_len - p_len + 1): |
| 42 | if text_hash == p_hash and text[i : i + p_len] == pattern: |
| 43 | return True |
| 44 | if i == t_len - p_len: |
| 45 | continue |
| 46 | # Calculate the https://en.wikipedia.org/wiki/Rolling_hash |
| 47 | text_hash = ( |
| 48 | (text_hash - ord(text[i]) * modulus_power) * alphabet_size |
| 49 | + ord(text[i + p_len]) |
| 50 | ) % modulus |
| 51 | return False |
| 52 | |
| 53 | |
| 54 | def test_rabin_karp() -> None: |
no outgoing calls