Suffix tree
Put every suffix of a string into one compressed tree whose edges are pieces of the text; afterwards any pattern can be found in O(pattern length).
A suffix tree is the trie of all suffixes of a string, with its non-branching paths compressed: each edge is a
piece of the text. With the end marker $ no suffix is a prefix of another, and each suffix gets its own leaf.
- Time:
O(n²) here (O(n) with Ukkonen's method) - Space:
O(n) nodes - Horowitz–Sahni, chapter 10
banana$; the tree has 7 leaves (one per suffix), and the edges “a”, “na” and “ana” are shared.
def suffix_tree(S):S = S + "$" # an end marker, so no suffix is a prefix of another and each ends at its own leaflabels = [""] # labels[v]: the text on the edge into node v (node 0 is the root)kids = [{}] # kids[v]: first letter of an outgoing edge → childrows = [[0, "-", "", "-"]] # for the picture: node, parent, edge label, suffix number at a leaffor i in range(len(S)):rest = S[i:]v = 0while True:if rest[0] not in kids[v]:labels.append(rest)kids.append({})kids[v][rest[0]] = len(labels) - 1rows.append([len(labels) - 1, v, rest, i])breakc = kids[v][rest[0]]label = labels[c]k = 0while k < len(label) and label[k] == rest[k]:k = k + 1if k == len(label):v = crest = rest[k:]continue# The suffix leaves the edge after k letters: split the edge there.mid = len(labels)labels.append(label[:k])kids.append({label[k]: c})kids[v][rest[0]] = midlabels[c] = label[k:]rows.append([mid, v, label[:k], "-"])rows[c][1] = midrows[c][2] = label[k:]v = midrest = rest[k:]return len(labels)
Start
The table is still empty.
Local variables
Orange = changed in this step
Call stack
- suffix_tree()line 1
Explanation
The idea
A suffix tree is the trie of all suffixes of a string, with its non-branching paths compressed: each edge is a
piece of the text. With the end marker $ no suffix is a prefix of another, and each suffix gets its own leaf.
The simple construction
Insert the suffixes one by one from the root:
- if no edge starts with the next letter, hang the rest of the suffix on a new leaf;
- if a whole edge label matches, go down it;
- if the suffix leaves an edge in the middle, split the edge there and make an inner node.
This takes O(n²); Ukkonen's method builds the same tree in O(n).
Uses
Finding any pattern in O(m), the longest repeated substring (the deepest inner node), the longest common substring
of two strings, and more.
What to watch in the trace
- The table lists every node: its parent, the label of the edge into it, and, for leaves, the suffix number.