The vocabulary and the theory that the algorithms rest on.

Definitions

TermMeaning
Substringa contiguous block,
Subsequenceany subset of positions, order preserved (not contiguous)
Prefix · Proper prefix: not the whole string
Suffix
Bordera string that is both a proper prefix and a proper suffix
Period for all valid
Rotation
Palindromeequal to its own reverse

A string of length has substrings (not all distinct) and subsequences.

The border-period duality

has a border of length iff has a period .

This single equivalence is why the prefix function — which computes the longest border of every prefix — is such a powerful primitive. It answers questions about periodicity for free.

All periods. Following the border chain enumerates every border, hence every period, in .

Smallest period. . The string is a full repetition of that period iff .

int smallestPeriod(const string& s) {
    vector<int> pi = prefixFunction(s);
    return s.size() - pi.back();
}
bool isRepetition(const string& s) {
    int p = smallestPeriod(s);
    return p != (int)s.size() && s.size() % p == 0;
}

The periodicity lemma (Fine and Wilf)

If has periods and with , then it also has period .

The bound is tight. This lemma underlies the linear-time constant-space matching algorithms (Galil-Seiferas, Crochemore-Perrin) and the analysis of runs.

Lexicographic order

Compare character by character; if one string is a prefix of the other, the shorter one is smaller. Note that lexicographic order is not length order — "z" > "abc".

Counting distinct substrings

MethodComplexity
Suffix array + LCP,
Suffix automaton,
Hashing + a set per length
Trie of all suffixes

The suffix automaton formula is the cleanest: each state represents a set of substrings of consecutive lengths, and their count is exactly .

Runs and repetitions

A run is a maximal periodic substring with period .

The runs theorem (Bannai et al., 2015): a string of length has fewer than runs, and they can all be found in .

Runs are found via Lyndon roots plus longest-common-extension queries. The older Main-Lorentz divide and conquer is easier to implement and usually sufficient.

Choosing a tool

TaskTool
Find one pattern in a textKMP, Z, or hashing
Find many patternsAho-Corasick
Compare arbitrary substringshashing, or suffix array + LCP
Count distinct substringssuffix automaton
Longest common substring of two stringssuffix automaton of one, run the other through it
All palindromic substringsEertree or Manacher
Periods and bordersprefix function
Smallest rotationBooth or Duval
-th substring lexicographicallysuffix automaton

See also: Prefix Function · String Hashing · Strings