← Назад к алгоритмам со строками

Алгоритм Кнута-Морриса-Пратта (КМП)

Поиск всех вхождений подстроки в строку за O(n + m)

🐍 Python
def f(p):
    m = len(p)
    A = [0] * m
    j = 0
    for i in range(1, m):
        while j > 0 and p[i] != p[j]:
            j = A[j - 1]
        if p[i] == p[j]:
            j += 1
        A[i] = j
    return A

def kmp(s, p):
    n = len(s)
    m = len(p)
    A = f(p)
    Z = []
    j = 0
    for i in range(n):
        while j > 0 and s[i] != p[j]:
            j = A[j - 1]
        if s[i] == p[j]:
            j += 1
        if j == m:
            Z.append(i - m + 1)
            j = A[j - 1]
    return Z

s = input()
p = input()
ANS = kmp(s, p)
print(len(ANS))
print(*[x + 1 for x in ANS])
⚙️ C++
#include <bits/stdc++.h>
using namespace std;

vector<int> f(const string& p) {
    int m = p.size();
    vector<int> A(m, 0);
    int j = 0;
    for (int i = 1; i < m; i++) {
        while (j > 0 && p[i] != p[j]) {
            j = A[j - 1];
        }
        if (p[i] == p[j]) {
            j++;
        }
        A[i] = j;
    }
    return A;
}

vector<int> kmp(const string& s, const string& p) {
    int n = s.size();
    int m = p.size();
    vector<int> A = f(p);
    vector<int> Z;
    int j = 0;
    for (int i = 0; i < n; i++) {
        while (j > 0 && s[i] != p[j]) {
            j = A[j - 1];
        }
        if (s[i] == p[j]) {
            j++;
        }
        if (j == m) {
            Z.push_back(i - m + 1);
            j = A[j - 1];
        }
    }
    return Z;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    string s, p;
    cin >> s >> p;
    
    vector<int> ans = kmp(s, p);
    cout << ans.size() << "\n";
    for (int x : ans) {
        cout << x + 1 << " ";
    }
    
    return 0;
}

Как работает алгоритм КМП?

Алгоритм Кнута-Морриса-Пратта (КМП) — это эффективный алгоритм поиска всех вхождений образца в текст за линейное время O(n + m), где n — длина текста, m — длина образца.

Ключевая идея: При несовпадении символов не возвращаться к началу образца, а использовать информацию о предыдущих совпадениях (префикс-функция).

Префикс-функция (функция f)

Для каждого префикса образца вычисляется длина наибольшего собственного префикса, который является также суффиксом.

Алгоритм поиска

Временная сложность: O(n + m) — каждый символ текста и образца обрабатывается не более двух раз.

Пространственная сложность: O(m) для хранения префикс-функции.

Преимущества: Работает за линейное время, не требует дополнительной памяти, кроме массива для префикс-функции.

Формат ввода и вывода

Ввод:

Вывод:

Пример ввода:

abacabadabacaba
aba

Вывод:

4
1 5 9 13

Пояснение: образец "aba" встречается в позициях 1, 5, 9, 13 (1-индексация).

Попробовать алгоритм КМП онлайн

Введите текст и образец для поиска:

Результат появится здесь...