String Algorithms — Master Recap and Pattern Cheatsheet

Sanjeev SharmaSanjeev Sharma
6 min read

Advertisement

String Algorithms Master Recap

Complete cheatsheet for all 20 string algorithm problems in this series, with algorithm selection guide and complexity reference.

Problem Index

#ProblemAlgorithmComplexity
00Complete Guide6 patterns + complexity table
01KMP SearchFailure functionO(n+m)
02Z-AlgorithmZ-arrayO(n+m)
03Rabin-KarpRolling hashO(n+m) avg
04ManacherPalindrome expansionO(n)
05String HashingPolynomial hashO(1) query
06Suffix ArrayDC3 / SA-ISO(n log n)
07Longest Common SubstringDPO(nm)
08String DPEdit distance, LCSO(nm)
09Anagram ProblemsFrequency vectorO(n)
10Palindrome SuiteExpand, DP, min-cutVarious
11Word Search I/IIDFS + TrieO(MN4^L)
12Encode/DecodeLength-prefixO(n)
13Shortest PalindromeKMP on s+'#'+revO(n)
14Distinct SubstringsSuffix array + LCPO(n log n)
15String CompressionRun-lengthO(n)
16Trie AdvancedXOR trie, palindrome pairsO(n*L)
17Meta/Google StringsNo-repeat window, valid parensO(n)
18Aho-CorasickMulti-pattern automatonO(n+m+z)
19Master RecapThis file

Algorithm Selection Guide

Single pattern search in text?
  → KMP O(n+m) — exact match, worst-case guaranteed
  → Rabin-Karp O(n+m) expected — multiple length patterns
 
All prefix occurrences / repeated substring?
  → Z-algorithm O(n+m)
  → KMP failure function at last position
 
Longest palindromic substring?
  → Manacher O(n) — fastest
  → Expand around center O(n^2) — simpler to implement
 
O(1) substring comparison?
  → Polynomial string hashing with prefix array
 
Lexicographic substring queries (LCP, distinct count)?
  → Suffix array O(n log n) build + O(1) LCP
 
Multi-pattern search?
  → Aho-Corasick O(n + total_pattern_length + z)
 
Edit distance / LCS?
  → Classic DP O(nm), optimize with rolling array to O(n)
 
Count palindromic substrings?
  → Expand O(n^2) or Manacher O(n)

Complexity Summary

AlgorithmTimeSpaceBest For
KMPO(n+m)O(m)Single pattern, worst-case guarantee
Z-functionO(n+m)O(n+m)Prefix occurrences
Rabin-KarpO(n+m) avgO(1)Multiple patterns, expected bound
ManacherO(n)O(n)All palindromes in one pass
String hashO(n) build, O(1) queryO(n)Substring equality in O(1)
Suffix arrayO(n log^2 n)O(n)LCP, distinct substrings
Edit distanceO(nm)O(n) rollingSimilarity, alignment
Aho-CorasickO(n+m+z)O(m * ALPHA)Multi-pattern matching

KMP Failure Function Template

def build_lps(pattern):
    m = len(pattern)
    lps = [0] * m
    length = 0
    i = 1
    while i < m:
        if pattern[i] == pattern[length]:
            length += 1
            lps[i] = length
            i += 1
        elif length > 0:
            length = lps[length - 1]   # do NOT increment i here
        else:
            lps[i] = 0
            i += 1
    return lps

Rolling Hash Template

MOD = (1 << 61) - 1   # Mersenne prime
BASE = 131
 
def build_hash(s):
    n = len(s)
    h = [0] * (n + 1)
    p = [1] * (n + 1)
    for i in range(n):
        h[i+1] = (h[i] * BASE + ord(s[i])) % MOD
        p[i+1] = p[i] * BASE % MOD
    def get(l, r):  # hash of s[l..r] inclusive, 0-indexed
        return (h[r+1] - h[l] * p[r-l+1]) % MOD
    return get

Z-Algorithm Template

def z_function(s):
    n = len(s)
    z = [0] * n
    z[0] = n
    l = r = 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

Common Pitfalls

  1. KMP: forgetting j = lps[j-1] on mismatch. The whole point is NOT resetting j to 0.
  2. KMP on combined string for Shortest Palindrome: forgetting the # separator. Without it, the LPS bleeds across the boundary.
  3. Rolling hash: not using a Mersenne prime modulus. Small primes collide frequently on adversarial inputs.
  4. Manacher: mixing 0-indexed and 1-indexed. Insert # separators consistently and never mix conventions.
  5. Aho-Corasick: forgetting to propagate output links. Patterns that are suffixes of other patterns will be missed.
  6. Suffix array: using naive O(n^2 log n) sort. Build with the O(n log n) doubling approach for large n.

Interview Mindset

  • For single pattern search, KMP is the expected O(n+m) answer. Always explain the failure function, not just the mechanics.
  • For palindromes, offer Manacher as the O(n) solution but acknowledge that expanding from center is simpler if Manacher implementation is not required.
  • For hashing problems, mention the double-hash technique (two bases/moduli) to reduce collision probability.
  • When a problem involves many string queries on the same text, think suffix array or hashing — not repeated KMP.

Key Takeaways

  • KMP achieves O(n+m) by never moving the text pointer backward — the failure function encodes the pattern's self-similarity.
  • The Z-array z[i] = length of longest substring starting from s[i] that matches a prefix of s — directly enables pattern search by concatenating pattern + '#' + text.
  • Manacher's algorithm computes all palindromic substrings in O(n) by exploiting previously computed palindrome radii to skip redundant checks.
  • Rolling hash enables O(1) substring comparison after O(n) preprocessing — use a Mersenne prime modulus to minimize collisions.
  • Aho-Corasick extends KMP failure links to a trie, enabling simultaneous O(n + m + z) search for k patterns in a single text pass.
  • Suffix arrays solve the hardest substring problems (LCP, distinct substring count, lexicographic ordering) in O(n log n) space and time.
  • The right algorithm depends on the query type: single pattern → KMP; multi-pattern → Aho-Corasick; palindromes → Manacher; substring equality → hashing.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading