Articles

Suffix Arrays Explained: Fast String Search

A suffix array sorts every suffix of a string into one compact index, enabling binary-search pattern matching without a full suffix tree.

The Lycoris Team The Lycoris Team · · 4 min read
Letterpress printing type blocks

A suffix array is a sorted list of every suffix of a string, represented compactly as an array of starting indices rather than the substrings themselves. It’s a way to answer “does this pattern appear in this text, and where” using binary search instead of scanning, and it does so with far less memory overhead than the data structure it’s usually compared against, the suffix tree.

What a suffix is, and why sorting all of them helps

Every position in a string marks the start of a suffix — the substring running from that position to the end of the string. For the string banana, the suffixes are banana, anana, nana, ana, na, and a. A suffix array doesn’t store these substrings directly; it stores the starting index of each suffix, sorted according to how the suffixes compare alphabetically:

Suffixes of "banana" sorted:
a       (index 5)
ana     (index 3)
anana   (index 1)
banana  (index 0)
na      (index 4)
nana    (index 2)

Suffix array: [5, 3, 1, 0, 4, 2]

Once every suffix is sorted, searching for whether a pattern exists in the text becomes a binary search problem: any occurrence of a pattern in the text is, by definition, the prefix of some suffix, and because all suffixes are sorted, every suffix that starts with your pattern sits in one contiguous block of the array. Binary search finds the edges of that block in logarithmic time, the same principle behind searching any sorted structure — see binary search trees explained for the general idea applied to a different structure.

How suffix array search compares to other string algorithms

Algorithms like KMP and Rabin-Karp are built to search for one pattern in one pass over the text, in linear time relative to the text length. That’s efficient for a single search, but if you need to search the same text repeatedly for many different patterns, redoing a linear scan every time wastes the fact that the text itself never changes between searches.

A suffix array flips the cost structure: building it takes some upfront work, but once built, each subsequent search against that same text is a fast binary search rather than a fresh scan. It’s the same tradeoff behind building an index in a database — pay a cost once, then benefit from it on every query afterward, rather than paying the full scan cost every single time.

Suffix array vs suffix tree

A suffix tree stores the same information — every suffix of a string — but as an actual tree structure where common prefixes are shared along tree paths, similar in spirit to how a trie shares prefixes across stored strings. Suffix trees support some queries even faster than a suffix array’s binary search, but at a real cost: each node needs pointers to its children, and that per-node overhead adds up to substantially more memory than a suffix array, which is just a flat array of integers.

Suffix arraySuffix tree
StructureSorted array of suffix start indicesTree with shared prefix paths
Memory overheadLow — one integer per suffixHigher — per-node pointers and structure
Pattern searchBinary search, O(m log n) for pattern length mDirect tree walk, often O(m)
Construction complexityMore involved to build efficientlyMore involved, larger constant factors
Practical usePreferred in memory-constrained or large-text settingsPreferred when raw query speed matters more than memory

In practice, suffix arrays are the more commonly deployed structure precisely because of that memory difference — for genome-scale text or large document corpora, the gap between “an array of integers” and “a tree of pointer-laden nodes” is often decisive.

Augmenting with the LCP array

Suffix arrays are frequently paired with a longest common prefix (LCP) array, which records how many leading characters two adjacent suffixes in the sorted order share. This addition speeds up several operations — finding the longest repeated substring in a text, or narrowing binary search ranges — without giving up the suffix array’s memory advantage over a full tree. It’s a common pattern in algorithm design generally: keep the compact primary structure, and add a small auxiliary array to recover some of the speed a heavier structure would otherwise provide.

Where this shows up in practice

Suffix arrays underpin full-text search over large, mostly static bodies of text — genome sequence matching, compressed full-text indexes, and some implementations of the Burrows-Wheeler transform used in data compression all build on the same sorted-suffix idea. They’re a good fit whenever the text is large, queried repeatedly, and doesn’t change often enough to make rebuilding the index a bottleneck — a very different profile from streaming or single-pass text search, where an algorithm like KMP that needs no preprocessing of the text itself is the better fit. For a sense of how the runtime cost is usually expressed and compared across approaches like this, see what Big O notation is.

The takeaway

A suffix array turns every suffix of a string into a sorted, compact index that supports binary-search pattern matching, trading a one-time construction cost for fast repeated queries against the same text. It gives up a little raw query speed compared to a suffix tree, but in exchange uses far less memory, which is why it’s the more common choice for large-scale text search in practice. Pair it with an LCP array when you need to recover some of that speed without giving up the compact representation.

The Lycoris Team The Lycoris Team · · 4 min read

The Rope Data Structure: Editing Huge Strings Efficiently

A rope is a binary tree of string chunks that makes inserting, deleting, and slicing huge strings fast, which is why text editors use it over plain arrays.

#Computer Science #Data Structures #Algorithms
The Lycoris Team The Lycoris Team · · 4 min read

Memoization vs. Tabulation in Dynamic Programming

Memoization caches results top-down via recursion; tabulation builds a table bottom-up with loops. Same technique, opposite direction, different tradeoffs.

#Computer Science #Algorithms #Data Structures
The Lycoris Team The Lycoris Team · · 4 min read

Manacher's Algorithm Explained

Manacher's algorithm finds the longest palindromic substring in linear time by reusing symmetry from palindromes already found, avoiding redundant checks.

#Computer Science #Algorithms #Data Structures