def naive_search(text, pattern): count = 0 for i in range(len(text) - len(pattern) + 1): match = True for j in range(len(pattern)): if text[i + j] != pattern[j]: match = False break if match: count += 1 return count print(naive_search('abababa', 'aba'))
The pattern 'aba' appears starting at indices 0, 2, and 4 in the text 'abababa'. So, the count is 3.
The prefix function stores for each position in the pattern the length of the longest prefix that matches a suffix ending at that position. This helps KMP skip unnecessary comparisons.
def rabin_karp(text, pattern): d = 256 q = 101 n = len(text) m = len(pattern) h = pow(d, m-1, q) p = 0 t = 0 result = [] for i in range(m): p = (d * p + ord(pattern[i])) % q t = (d * t + ord(text[i])) % q for i in range(n - m + 1): if p == t: if text[i:i+m] == pattern: result.append(i) if i < n - m: t = (d * (t - ord(text[i]) * h) + ord(text[i + m])) % q if t < 0: t += q return result print(rabin_karp('abracadabra', 'abra'))
The pattern 'abra' appears at index 0 and index 7 in the text 'abracadabra'. The Rabin-Karp algorithm finds these indices.
def prefix_function(pattern): pi = [0] * len(pattern) k = 0 for q in range(1, len(pattern)): while k > 0 and pattern[k] != pattern[q]: k = pi[k-1] if pattern[k] == pattern[q]: k += 1 pi[q] = k return pi print(prefix_function('ababc'))
The code uses pi[k] but k can be equal to len(pattern), causing an IndexError.
The sliding window approach with two pointers and a frequency map efficiently finds the minimum window containing all pattern characters by expanding and contracting the window.
