KMP

빠른 설명

KMP(Knuth-Morris-Pratt)는 문자열에서 패턴을 빠르게 찾는 알고리즘이다. 실패했을 때 어디까지 되돌아가야 하는지를 prefix function으로 미리 계산한다.

언제 쓰는가

  • 긴 문자열에서 특정 패턴이 등장하는 위치를 모두 찾을 때
  • 단순 검색 이 시간 초과가 날 때
  • 접두사와 접미사 정보가 필요한 문자열 문제

시간복잡도

  • 전처리:
  • 검색:
  • 전체:

참고자료

C++ 코드

#include <algorithm>
#include <deque>
#include <functional>
#include <iostream>
#include <queue>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;
 
vector<int> prefix_function(const string& s) {
    int n = s.size();
    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];
        }
        if (s[i] == s[j]) j++;
        pi[i] = j;
    }
 
    return pi;
}
 
vector<int> kmp_search(const string& text, const string& pattern) {
    string combined = pattern + "#" + text;
    vector<int> pi = prefix_function(combined);
    vector<int> result;
    int m = pattern.size();
 
    for (int i = m + 1; i < (int)combined.size(); i++) {
        if (pi[i] == m) {
            result.push_back(i - 2 * m);
        }
    }
 
    return result;
}
 
int main() {
    auto pos = kmp_search("ababcababd", "abab");
    for (int x : pos) cout << x << ' ';
}

Python 코드

def prefix_function(s):
    pi = [0] * len(s)
 
    for i in range(1, len(s)):
        j = pi[i - 1]
        while j > 0 and s[i] != s[j]:
            j = pi[j - 1]
        if s[i] == s[j]:
            j += 1
        pi[i] = j
 
    return pi
 
def kmp_search(text, pattern):
    combined = pattern + "#" + text
    pi = prefix_function(combined)
    result = []
    m = len(pattern)
 
    for i in range(m + 1, len(combined)):
        if pi[i] == m:
            result.append(i - 2 * m)
 
    return result
 
print(kmp_search("ababcababd", "abab"))