String Algorithms Interview Guide: KMP, Rabin-Karp, and Pattern Matching
String algorithms appear in interviews at companies where text processing matters — search engines, compilers, genomics, security. The questions range from basic pattern matching to building tries for autocomplete. Understanding the underlying mechanics of each algorithm — not just the code — is what distinguishes candidates.
String Hashing
Polynomial rolling hash maps a string to an integer, enabling O(1) equality checks after O(n) preprocessing. The foundation of Rabin-Karp and many sliding window problems.
def string_hash(s, base=31, mod=10**9+7):
h = 0
power = 1
for c in s:
h = (h + (ord(c) - ord('a') + 1) * power) % mod
power = (power * base) % mod
return h
For substring hashing, precompute prefix hashes and powers to get hash of any substring in O(1):
def build_prefix_hash(s, base=31, mod=10**9+7):
n = len(s)
prefix = [0] * (n + 1)
power = [1] * (n + 1)
for i in range(n):
prefix[i+1] = (prefix[i] + (ord(s[i]) - ord('a') + 1) * power[i]) % mod
power[i+1] = (power[i] * base) % mod
return prefix, power
def get_hash(prefix, power, l, r, mod=10**9+7):
return (prefix[r+1] - prefix[l] * power[r-l+1]) % mod
Double hashing (two different mod values) reduces collision probability to near-zero for competitive reliability.
Rabin-Karp: Rolling Hash Pattern Matching
Rabin-Karp slides a hash window across the text, comparing hash values before character-by-character verification. Average O(n + m); O(nm) worst case due to collisions.
def rabin_karp(text, pattern):
n, m = len(text), len(pattern)
base, mod = 31, 10**9+7
def hash_str(s):
h, p = 0, 1
for c in s:
h = (h + ord(c) * p) % mod
p = (p * base) % mod
return h, p
ph, _ = hash_str(pattern)
th, tp = hash_str(text[:m])
results = []
if ph == th and text[:m] == pattern:
results.append(0)
for i in range(1, n - m + 1):
th = (th - ord(text[i-1])) % mod
th = (th * pow(base, mod-2, mod)) % mod # modular inverse
th = (th + ord(text[i+m-1]) * tp) % mod
if th == ph and text[i:i+m] == pattern:
results.append(i)
return results
In practice, the additive rolling hash (subtract outgoing character, add incoming character divided by power) is simpler to implement correctly. Know both forms.
KMP: Knuth-Morris-Pratt
KMP achieves guaranteed O(n + m) by precomputing a failure function that tells you how far to fall back in the pattern without restarting.
The failure function (also called prefix function or LPS — Longest Proper Prefix which is also Suffix):
def build_failure(pattern):
m = len(pattern)
fail = [0] * m
j = 0
for i in range(1, m):
while j > 0 and pattern[i] != pattern[j]:
j = fail[j-1]
if pattern[i] == pattern[j]:
j += 1
fail[i] = j
return fail
def kmp_search(text, pattern):
fail = build_failure(pattern)
results = []
j = 0
for i, c in enumerate(text):
while j > 0 and c != pattern[j]:
j = fail[j-1]
if c == pattern[j]:
j += 1
if j == len(pattern):
results.append(i - len(pattern) + 1)
j = fail[j-1]
return results
Interview insight: the failure function itself encodes all proper prefix-suffix relationships of the pattern. KMP is also used to find the shortest repeating unit of a string: if n % (n - fail[n-1]) == 0, the string is a repetition of its first n - fail[n-1] characters.
Z-Algorithm
The Z-array for string s stores at each position i the length of the longest substring starting at i that is also a prefix of s. Z[0] is conventionally 0 or n.
def z_function(s):
n = len(s)
z = [0] * n
l, r = 0, 0
for i in range(1, n):
if i < r:
z[i] = min(r - i, z[i - l])
while i + z[i] < n and s[z[i]] == s[i + z[i]]:
z[i] += 1
if i + z[i] > r:
l, r = i, i + z[i]
return z
Pattern matching with Z: concatenate pattern + '$' + text, compute Z-array. Any position where Z-value equals len(pattern) is a match. The $ separator prevents matches that span the boundary.
Trie for String Problems
A trie (prefix tree) enables O(m) insert and search where m is string length. Essential for autocomplete, spell checking, and problems involving common prefixes.
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for c in word:
if c not in node.children:
node.children[c] = TrieNode()
node = node.children[c]
node.is_end = True
def search(self, word):
node = self.root
for c in word:
if c not in node.children:
return False
node = node.children[c]
return node.is_end
def starts_with(self, prefix):
node = self.root
for c in prefix:
if c not in node.children:
return False
node = node.children[c]
return True
For XOR problems (Maximum XOR of Two Numbers in an Array), build a binary trie — each node has children 0 and 1.
Common LeetCode String Patterns
| Pattern | Technique | Example Problems |
|---|---|---|
| Pattern matching | KMP / Rabin-Karp | Find All Anagrams, Repeated Substring Pattern |
| Common prefix | Trie | Word Search II, Replace Words |
| Sliding window + count | HashMap | Minimum Window Substring, Permutation in String |
| Palindrome detection | Manacher / expand | Longest Palindromic Substring |
| Anagram grouping | Sort-as-key / hash | Group Anagrams |
| String construction | Stack | Decode String, Remove Duplicate Letters |
Suffix Arrays (Conceptual)
A suffix array is a sorted array of all suffixes of a string. Building one in O(n log n) is interview-level knowledge at top companies (Google, Jane Street). The key insight: sort suffixes in rounds, doubling the compared prefix length each time. Combined with the LCP array, suffix arrays solve substring search, longest repeated substring, and longest common substring in O(n) or O(n log n).
For most interviews, you won't need to implement suffix arrays from scratch — but knowing they exist, what they solve, and their complexity demonstrates depth that impresses senior interviewers.
String algorithm mastery is not about memorizing code. It is about understanding why each algorithm works — the invariants maintained, the guarantees provided, and the tradeoffs accepted.
Ready to practice for your next interview? Interview Simulator gives you AI-powered feedback on your responses — behavioral, technical, and system design. Start with 3 free practice interviews today.
Try Interview Simulator free →
Don't neglect behavioral preparation — see our behavioral interview guide.
For technical interview preparation, our system design guide is essential reading.
Master the most common coding interview patterns to ace your technical rounds.
Your resume is the first impression — get it right with our resume guide.
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "String Algorithms KMP, Rabin-Karp, and Pattern Matching",
"description": "Master string algorithm interviews with KMP, Rabin-Karp rolling hash, Z-algorithm, trie, and pattern matching templates in Python.",
"datePublished": "2026-03-20",
"author": {
"@type": "Organization",
"name": "CodeSwiftr Team"
},
"url": "https://codeswiftr.com/blog/string-algorithms-interview-guide"
}
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is the best way to practice String for interviews?",
"acceptedAnswer": {
"@type": "Answer",
"text": "The most effective approach is deliberate, pattern-based practice. Start by understanding the core String patterns (there are typically 5–10 fundamental patterns). Solve 3–5 representative problems per pattern before moving on. Use spaced repetition — revisit harder problems after 3–5 days. Time yourself: aim to solve medium-difficulty problems within 20–25 minutes."
}
},
{
"@type": "Question",
"name": "How frequently do String questions appear in FAANG interviews?",
"acceptedAnswer": {
"@type": "Answer",
"text": "String questions appear in approximately 60–80% of FAANG coding interviews. Google and Meta have the highest frequency; Amazon tends to favour dynamic programming and graph problems. Understanding the String fundamentals is non-negotiable for any FAANG or FAANG-adjacent interview loop."
}
},
{
"@type": "Question",
"name": "What are the most common mistakes candidates make with String?",
"acceptedAnswer": {
"@type": "Answer",
"text": "The most common mistakes are: (1) jumping to code before fully understanding the problem — always clarify constraints and edge cases first; (2) not communicating your thought process — interviewers want to follow your reasoning; (3) skipping complexity analysis — always state time and space complexity after your solution; (4) ignoring edge cases like empty inputs, single elements, or overflow conditions."
}
},
{
"@type": "Question",
"name": "How many String problems should I solve before interviewing?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Quality beats quantity. Solve 30–50 String problems spanning easy, medium, and hard difficulties, with a 20/60/20 split. Focus on understanding why each solution works rather than memorising answers. For each problem, be able to explain: the brute-force approach, the optimised solution, the time/space complexity, and at least two edge cases."
}
}
]
}
Explore Related Topics
- Interval Problems for Coding Interviews: Patterns and...
- Math-Based Coding Interview Problems: Patterns and Tricks
- Number Theory Patterns for Coding Interviews