ADVANCED TECHNIQUES / ALGORITHM BRIEF

String matching

String matching finds occurrences of a pattern of length m inside a text of length n.

AdvancedPhase 08 / Topic 3 of 7Mental modelComplexityEdge cases
01

Overview

String matching finds occurrences of a pattern of length m inside a text of length n. The naive approach checks every starting position and costs O(n x m) in the worst case. Linear-time algorithms avoid re-examining characters by preprocessing the pattern.

KMP (Knuth-Morris-Pratt) builds an LPS array: for each prefix of the pattern, the length of its longest proper prefix that is also a suffix. On a mismatch, it jumps the pattern forward using that array instead of restarting, giving O(n + m). The Z-algorithm and rolling hashes (Rabin-Karp) are the other common linear approaches.

Not re-reading what you already know

If you are searching for 'ABABC' and have matched 'ABAB' before failing, you already know the last 'AB' you read is also the start of the pattern. KMP slides the pattern so that 'AB' lines up and continues from there, instead of starting over one character later.

02

When to use it

  • Find the first or all occurrences of a pattern in text.
  • Repeated or periodic structure in a string (repeated substring pattern).
  • Shortest palindrome and prefix-suffix problems.
  • Large inputs where O(n x m) is too slow.
03

Problem patterns it solves

Find a pattern

Recognize it when: index of first occurrence, count occurrences.

  • 28. Find the Index of the First Occurrence in a String
  • 1392. Longest Happy Prefix
Periodicity from LPS

Recognize it when: string made of a repeated block.

  • 459. Repeated Substring Pattern
  • 686. Repeated String Match
Prefix equals suffix

Recognize it when: longest prefix that is also a suffix; shortest palindrome.

  • 1392. Longest Happy Prefix
  • 214. Shortest Palindrome
Rotation check

Recognize it when: is one string a rotation of another: search in s + s.

  • 796. Rotate String
Multiple patterns

Recognize it when: many patterns at once (Aho-Corasick or a trie).

  • 1032. Stream of Characters
  • 212. Word Search II
04

Where it is used in real software

Text editors and grep

Find in file, grep, and search in browsers use efficient string search algorithms such as Boyer-Moore variants.

Intrusion detection

Network security tools like Snort match thousands of attack signatures in traffic using Aho-Corasick.

Bioinformatics

Searching for gene sequences in DNA uses linear-time matching and suffix structures.

Plagiarism and spam filters

Detect known phrases or templates in documents and emails.

05

Key terms

LPS array
lps[i] = length of the longest proper prefix of pattern[0..i] that is also a suffix.
Proper prefix
A prefix that is not the whole string.
Z-array
z[i] = length of the longest substring starting at i that matches a prefix.
Boyer-Moore
Compares from the pattern's end and skips ahead using bad-character rules; fast in practice.
06

KMP in two phases

  1. 1
    Build LPS

    Walk the pattern with len = current matched prefix length. On match, len++ and lps[i] = len. On mismatch, fall back len = lps[len - 1] (or set 0).

  2. 2
    Search

    Walk the text with j = number of pattern characters matched.

  3. 3
    Match

    If text[i] === pattern[j], advance both; if j === m, a match ends at i.

  4. 4
    Mismatch

    If j > 0, set j = lps[j - 1] and retry the same text character. Otherwise advance i.

  5. 5
    Never move the text pointer backward

    That is why the total is O(n + m).

07

LPS array for pattern "ABABCABAB"

lps[i] = longest proper prefix of pattern[0..i] that is also its suffix

Step 1 / 9
icharPrefixLongest prefix = suffixlps[i]
0AA-0
1BAB-0
2AABAA1
3BABABAB2
4CABABC-0
5AABABCAA1
6BABABCABAB2
7AABABCABAABA3
8BABABCABABABAB4

NOWi: 0 | char: A | Prefix: A | Longest prefix = suffix: - | lps[i]: 0

After matching the whole pattern, KMP continues as if 4 characters (ABAB) are already matched, so it finds overlapping occurrences without rescanning the text. On a mismatch after matching ABABCABA (8 characters), it resumes with lps[7] = 3 characters matched.

08

Implementation

function buildLPS(pattern) {  const lps = new Array(pattern.length).fill(0);  let len = 0;  for (let i = 1; i < pattern.length; ) {    if (pattern[i] === pattern[len]) {      lps[i++] = ++len;    } else if (len > 0) {      len = lps[len - 1]; // try a shorter border    } else {      lps[i++] = 0;    }  }  return lps;} function kmpSearch(text, pattern) {  if (!pattern) return [0];  const lps = buildLPS(pattern);  const matches = [];  let j = 0;  for (let i = 0; i < text.length; i++) {    while (j > 0 && text[i] !== pattern[j]) j = lps[j - 1];    if (text[i] === pattern[j]) j++;    if (j === pattern.length) {      matches.push(i - j + 1);      j = lps[j - 1]; // continue for overlapping matches    }  }  return matches;} // 459. Repeated Substring Pattern using LPSfunction repeatedSubstringPattern(s) {  const lps = buildLPS(s);  const border = lps[s.length - 1];  const period = s.length - border;  return border > 0 && s.length % period === 0;} // 214. Shortest Palindrome: longest palindromic prefix via LPS of s + '#' + reverse(s)function shortestPalindrome(s) {  const rev = [...s].reverse().join("");  const lps = buildLPS(s + "#" + rev);  return rev.slice(0, s.length - lps.at(-1)) + s;}
09

Complexity and performance

Naive searchO(n x m)

Worst case like text aaaa...ab.

KMPO(n + m)

O(m) extra space for LPS.

Z-algorithmO(n + m)

Same bounds, different preprocessing.

Built-in indexOf / containsfast in practice

Implementations vary; worst case may be O(n x m).

10

Trade-offs

KMP vs built-in

In interviews you usually may use indexOf; implement KMP when asked, or when the LPS array itself is useful (periodicity, borders).

KMP vs Rabin-Karp

KMP is deterministic; Rabin-Karp is simpler to extend to multiple patterns and 2D, but relies on hashing and has collision risk.

11

Variants and related techniques

Aho-Corasick

A trie of many patterns with failure links (KMP on a trie); finds all patterns in one pass.

Suffix array / automaton

Answers many substring queries on one text after O(n log n) or O(n) preprocessing.

Manacher's algorithm

Finds the longest palindromic substring in O(n) using a similar reuse-of-work idea.

12

Common mistakes

  • Advancing i after a fallback in the LPS build.

    Fix: When len = lps[len - 1], stay on the same i and compare again.

  • Missing overlapping matches.

    Fix: After a full match set j = lps[j - 1], not 0.

  • Separator collisions in combined strings.

    Fix: Use a character that cannot appear in the input (#, $).

13

Interview questions

What does the LPS array represent?

For each position, the length of the longest proper prefix of the pattern that is also a suffix of the pattern up to that position. It tells KMP how much of the pattern is still matched after a mismatch.

Why is KMP O(n + m)?

The text pointer never moves backward. Each fallback reduces j, and j can only increase once per text character, so total fallbacks are bounded by n.

14

Practice problems

ProblemDifficultyWhat it trains
28. Find the Index of the First OccurrenceEasyImplement KMP.
796. Rotate StringEasySearch in s + s.
459. Repeated Substring PatternEasyPeriod from LPS.
1392. Longest Happy PrefixHardFinal LPS value.
214. Shortest PalindromeHardLPS of combined string.