Why Right-to-Left Matching Helps
At alignment $s$, Boyer–Moore compares $P[0\dots m)$ with $T[s\dots s+m)$ from right to left. A left-to-right mismatch usually rejects only the current start. A right-to-left mismatch may first prove that a long suffix matches, enabling both a bad-character shift and a good-suffix shift.
If the mismatch is at pattern index $j$, the suffix $P[j+1\dots m)$ has already matched. Any nearby valid alignment must place compatible pattern content over that text suffix. The bad-character rule uses the mismatching text symbol; the good-suffix rule uses the matched suffix. Search advances by the maximum positive safe shift.
Right-to-Left Trace
Search for $P=\text{"ABCDAB"}$ in $T=\text{"ZZCDABCDAB"}$.
At alignment $0$, comparisons from the right match B, A, D, and C; then $P[1]=\text{"B"}$ mismatches $T[1]=\text{"Z"}$. The good suffix is "CDAB". It has no earlier compatible occurrence, but its suffix "AB" is also a pattern prefix. Aligning that prefix with the final "AB" shifts the length-$6$ pattern by $6-2=4$. At alignment $4$, the complete window is "ABCDAB", so the match is found while starts $1$, $2$, and $3$ are safely skipped.
Strong Good-Suffix Cases
After a mismatch at $j$, let $G=P[j+1\dots m)$. In the first case, $G$ occurs earlier in the pattern. The strong rule chooses the rightmost earlier occurrence not preceded by the mismatching symbol $P[j]$; otherwise the shift would reproduce the known mismatch immediately.
If no compatible internal occurrence exists, align the longest suffix of $G$ that is also a prefix of $P$. This matched-prefix fallback preserves the only remaining overlap that could lead to a match. If no non-empty prefix qualifies, move beyond the matched suffix. After a full match, the same prefix structure aligns the pattern's longest proper border and preserves overlapping occurrences.
Building the Shift Tables
Strong preprocessing scans right to left. border_position[i] links the suffix beginning at $i$ to its next border candidate. When the characters preceding two candidate suffixes differ, the current suffix occurrence is compatible with the mismatch; record its displacement if that shift entry is still empty. Following border links tests progressively shorter suffixes.
The first pass fills internal-occurrence shifts. A second walk over the full pattern's border chain fills remaining entries with matched-prefix fallbacks. The table has length $m+1$: search uses shift[j + 1] after a mismatch at $j$ and shift[0] after a complete match.
Combining Heuristics and Guarantees
At mismatch $j$, the bad-character rule aligns the mismatching text symbol with its rightmost occurrence at or before $j$, or moves past it if absent. The good-suffix rule preserves the already matched suffix. Since each independently excludes smaller unsafe alignments, their maximum positive shift is safe.
Basic Boyer–Moore has excellent average behavior but can make $O(nm)$ comparisons on repetitive inputs. The Galil rule remembers regions already proved equal and supports linear worst-case searching with the full construction. Horspool uses the character aligned with the final pattern position, while Sunday uses the character immediately after the window; both simplify preprocessing but retain quadratic worst cases.
| Variant | Shift information | Preprocessing | Typical strength | Worst-case search | Best fit |
|---|---|---|---|---|---|
| Full Boyer–Moore | Bad character plus strong good suffix | $O(m+\sigma)$ with dense tables | Largest safe shift from both rules | $O(nm)$ for a basic loop | Long patterns and amortized preprocessing |
| BM with Galil rule | Full rules plus remembered matched regions | Full preprocessing plus bookkeeping | Avoids rechecking known regions | $O(n+m)$ with required construction | Worst-case-sensitive exact matching |
| Bad-character-only BM | Rightmost mismatching-symbol occurrence | $O(m)$ | Strong on large alphabets | $O(nm)$ | Simple large-alphabet search |
| Horspool | Symbol aligned with pattern end | $O(m+\sigma)$ or sparse equivalent | Small code and excellent constants | $O(nm)$ | Practical byte-string search |
| Sunday / Quick Search | Symbol after current window | $O(m+\sigma)$ or sparse equivalent | Full-length-plus-one shifts when absent | $O(nm)$ | In-memory search with safe lookahead |
| Naive left-to-right | No heuristic | $O(1)$ | Minimal setup | $O(nm)$ | Tiny inputs and exact baselines |