Two linear-time arrays that answer most single-pattern questions. The prefix function is the length of the longest proper border of (a proper prefix that is also a suffix); the Z-function is the length of the longest common prefix of and . Both match a pattern in ; also gives borders, periods and the KMP automaton (the DFA for “contains the pattern”, the basis of Aho–Corasick).

QuestionAnswer
all occurrences of in KMP (streaming, only of in memory), or / of
smallest period of ; is a power of a shorter string; that period divides and is (String Basics)
all borders / all periodsthe chain
occurrences of every prefix of in count values and propagate along borders
shortest string with as prefix and suffix
fewest characters to append to make a palindrome of at the end
strings of length avoiding DP over the KMP automaton (matrix power for huge )
LCP of and every suffix; is a rotation of ; search in
smallest period via smallest with
distinct substrings incrementallyeach appended character adds new substrings
prefix functionZ-function
meaninglongest border of the prefix ending at LCP of with
natural forperiods, borders, automata, multi-patternmatching, comparisons
conversion in (zToPi); both from the string in
vector<int> prefixFunction(const string& s) {
    int n = sz(s); vector<int> pi(n, 0);
    for (int i = 1; i < n; i++) {
        int j = pi[i - 1];
        while (j > 0 && s[i] != s[j]) j = pi[j - 1];        // fall back along borders
        if (s[i] == s[j]) j++;
        pi[i] = j;
    }
    return pi;
}
vector<int> kmpSearch(const string& text, const string& pat) {   // start positions, streaming over the text
    vector<int> res; if (pat.empty()) return res;
    vector<int> pi = prefixFunction(pat); int j = 0;
    for (int i = 0; i < sz(text); i++) {
        while (j > 0 && text[i] != pat[j]) j = pi[j - 1];
        if (text[i] == pat[j]) j++;
        if (j == sz(pat)) res.push_back(i - j + 1), j = pi[j - 1];
    }
    return res;
}
vector<int> prefixOccurrences(const string& s) {            // cnt[len] = #occurrences of s[0, len) in s, len = 0..n
    int n = sz(s); vector<int> pi = prefixFunction(s), cnt(n + 1, 0);
    for (int i = 0; i < n; i++) cnt[pi[i]]++;
    for (int i = n - 1; i > 0; i--) cnt[pi[i - 1]] += cnt[i];
    for (int i = 0; i <= n; i++) cnt[i]++;
    return cnt;
}
vector<array<int, 26>> kmpAutomaton(const string& s) {      // aut[state][c], states 0..n (n = full match), lowercase
    int n = sz(s); vector<int> pi = prefixFunction(s); vector<array<int, 26>> aut(n + 1);
    for (int i = 0; i <= n; i++) for (int c = 0; c < 26; c++) {
        if (i < n && c == s[i] - 'a') aut[i][c] = i + 1;
        else aut[i][c] = i == 0 ? 0 : aut[pi[i - 1]][c];
    }
    return aut;
}
vector<int> zFunction(const string& s) {
    int n = sz(s); vector<int> z(n, 0); if (n) z[0] = n;
    for (int i = 1, l = 0, r = 0; i < n; i++) {
        if (i < r) z[i] = min(r - i, z[i - l]);
        while (i + z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++;
        if (i + z[i] > r) l = i, r = i + z[i];
    }
    return z;
}
vector<int> zSearch(const string& text, const string& pat) {   // separator '\1' must occur in neither string
    string s = pat + '\1' + text; vector<int> z = zFunction(s), res;
    for (int i = sz(pat) + 1; i < sz(s); i++) if (z[i] >= sz(pat)) res.push_back(i - sz(pat) - 1);
    return res;
}
vector<int> zToPi(const vector<int>& z) {                   // O(n)
    int n = sz(z); vector<int> pi(n, 0);
    for (int i = 1; i < n; i++) for (int j = z[i] - 1; j >= 0 && !pi[i + j]; j--) pi[i + j] = j + 1;
    return pi;
}
string shortestPalindromeByAppending(const string& s) {     // append the fewest characters on the right
    string r(s.rbegin(), s.rend()); vector<int> pi = prefixFunction(r + '\1' + s);
    int keep = pi.back();                                   // longest palindromic suffix of s
    string add = s.substr(0, sz(s) - keep); reverse(all(add));
    return s + add;
}
ll distinctSubstringsIncremental(const string& s) {         // O(n^2) via z of reversed prefixes
    ll total = 0; string cur;
    for (char c : s) {
        cur += c; string rv(cur.rbegin(), cur.rend()); vector<int> z = zFunction(rv);
        int mx = 0; for (int i = 1; i < sz(rv); i++) mx = max(mx, z[i]);
        total += sz(cur) - mx;
    }
    return total;
}