AlgoPlusAlgoPlus
Learn/Data Structures & Algorithms
Lesson

Finite Automaton Matching

Compile the pattern into a DFA, then scan the text once following one transition per character — O(n).

9 min read Watch it move Build it

Finite-automaton matching bakes the pattern into a small machine — a DFA (deterministic finite automaton) — and then matching is almost nothing: read the text once, follow exactly one arrow per character, and you have your answer. All the cleverness is moved into building the machine up front.

States = how much matched so far

For a pattern of length m, the DFA has m + 1 states, numbered by how many leading characters of the pattern have matched: state 0 means *nothing matched*, state m is the accept state — reaching it means the pattern just appeared. A precomputed transition table answers, for every state and every possible next character of the alphabet (Σ), which state to move to.

A worked DFA for ABA over {A, B}

state | meaning   |  A   |  B
------+-----------+------+-----
  0   | ""        |  1   |  0
  1   | "A"       |  1   |  2
  2   | "AB"      |  3   |  0
  3   | "ABA" ✓   |  1   |  2   <- accept

The forward arrows are obvious — state 2 on A advances to the accepting state 3. The subtle ones are the fall-backs. From state 1 ("A") reading another A stays at 1: the new A is itself a fresh one-character match. From the accept state 3, reading B goes to 2 because the text now ends in "AB", the longest pattern prefix that is still alive. Each transition lands on the longest pattern prefix that is a suffix of what was just read — the same prefix-suffix idea that powers KMP.

function automatonSearch(text, dfa, m) {
  let state = 0;
  const hits = [];
  for (let i = 0; i < text.length; i++) {
    state = dfa[state][text[i]];   // one lookup per character
    if (state === m) hits.push(i - m + 1);  // reached accept
  }
  return hits;
}
  1. 1Build the transition table: for each state and each alphabet symbol, find the longest pattern prefix that is a suffix of the matched-text-plus-symbol.
  2. 2Start the scan in state 0.
  3. 3For each text character, look up the next state in the table — one constant-time step.
  4. 4Whenever the scan enters the accept state, record a match ending here.
All the work is in the build
The scan is gorgeously simple — one array lookup per character, no backtracking, no comparisons. The price is the table: building it costs O(m × |Σ|) because every state needs an entry for every alphabet symbol.
Same engine as KMP
KMP and the DFA are two faces of one idea. KMP stores a compact O(m) failure table and computes fall-backs on the fly; the automaton pre-bakes every (state, character) answer into a full table for a branch-free scan. Trade memory for a simpler inner loop.
OperationTimeSpace
Build DFA · |Σ| = alphabet sizeO(m·|Σ|)O(m·|Σ|)
Scan text · one transition per characterO(n)O(1)
Check yourself
Why does scanning the text with the DFA take only O(n), independent of the pattern length?