Processing math: 100%
We will find a way, we always have.

-interstellar

Computer Science/알고리즘

[알고리즘] KMP 알고리즘

Redddy 2023. 9. 15. 00:28

문자열 NH가 주어졌을 때 NH 있는지 찾는 문자열 검색 알고리즘에 대해 알아보자. 

 

나이브하게 접근해보면 N의 첫문자부터 마지막문자까지 H와 하나하나 비교해가면서 일치하는지 판별할 수 있고 해당 솔루션의 시간복잡도는 O(|N||H|) 이다. 

문자열의 길이가 짧다면 해당 접근방법도 구현도 쉽고 나쁘지만은 않다. 하지만 문자열의 길이가 커진다면 제한시간내에 동작하지 못하게 된다.  

 

N[k...i1]H[...i1] 까지는 문자열이 일치하였지만 H[i] 문자에서 일치하지 않는경우 다시 N[k+1] 부터 비교하는 것이 아니라 이미 H[...i1]까지 어떤 문자가 있는지 알고 있으니 보지 않아도 H[k+1]H[0]과 같은지 다른지는 알 수 있지 않을까? 라는 아이디어에서 온 것이 바로 KMP 알고리즘 이다. 

 

커누스 모리스 프랫 (Knuth Morris Pratt) - KMP 알고리즘

KMP 알고리즘은 실패 함수를 만들어서 문자열 비교 실패시 다음 시작 위치를 어디로 잡아야 할지 알려준다. 

 

pi[i]=N[...i]의 접두사도 되고 접미사도 되는 문자열의 최대 길이

 

N = "aabaabac" 일때 실패함수 pi가 어떻게 구성되는지 살펴보자. 

 

i N[...i] 접두사이면서 접미사인 최대 문자열 pi[i]
0 a 없음 0
1 aa a 1
2 aab 없음 0
3 aaba a 1
4 aabaa aa 2
5 aabaab aab 3
6 aabaaba aaba 4
7 aabaabac 없음 0

 

여기서 중요한 점은 시작 위치를 움직인 이후 첫 글자부터 다시 대응시킬 필요가 없다는 것이다.  

 

아래의 코드는 실패 함수 구현 코드이다. 

 

 

1
2
3
4
5
6
7
8
9
10
def kmp(n, string, pattern):
    pi = [0]*n
    i = 0
    for j in range(1, n):
        while i > 0 and pattern[i] != pattern[j]:
            i = pi[i-1]
        if pattern[i] == pattern[j]:
            i += 1
            pi[j] = i
    return pi
cs

 

실패 함수를 구현했다면 해당 배열을 가지고 문자열 비교하는 아이디어는 실패 함수 만들었던 아이디어와 같다.

 

-작성중-.