Notice
suyeonme
[Algorithm/문자열 탐색] KMP(Knuth–Morris–Pratt) 알고리즘 본문
1. KMP(Knuth–Morris–Pratt) 알고리즘이란?
- 텍스트와 패턴 사이에 겹치는 부분을 찾아내 검사를 다시 시작할 위치를 구하여 패턴을 한번에 많이 옮기는 알고리즘이다.
- "몇번째 문자부터 다시 검색할지"에 대한 값을 미리 표로 만들어 검사를 시작할 위치를 구한다. 즉 패턴과 텍스트가 불일치할 경우, 그 전에 검사했던 텍스트의 문자를 표에 작성하여 불필요한 검사는 생략한다.
- 시간 복잡도는 O(n)이다.
2. 동작 방식
- skip[]은 패턴에서 접두사(prefix)와 접미사(suffix)가 일치하는 최대 길이를 저장하는 배열이다.
- 접두사와 접미사가 일치하지 않으면, 접미사를 가리키는 인덱스를 1 증가한다.
- 접두사와 접미사가 일치하면, 접두사를 가리키는 인덱스와 접미사를 가리키는 인덱스를 1 증가한다.
문자열 ABAABAB를 예시로 들어보자
index | text | skip[index] |
0 | A | 0 |
1 | AB | 0 |
2 | ABA | 1 |
3 | ABAA | 1 |
4 | ABAAB | 2 |
5 | ABAABA | 3 |
6 | ABAABAB | 2 |
3. 구현하기
static int kmpMatch(String text, String pattern) {
int pt = 1; // text 커서
int pp = 0; // pattern 커서
int[] skip = new int[pattern.length() + 1]; // 건너뛰기 표
// 건너뛰기 표 생성
skip[pt] = 0;
while(pt != pattern.length()) {
if(pattern.charAt(pt) == pattern.charAt(pp)) {
skip[++pt] = ++pp;
} else if(pp == 0) {
skip[++pt] = pp;
} else {
pp = skip[pp];
}
}
// 문자열 검색
pt = pp = 0;
while(pt != text.length() && pp != pattern.length()) {
if(text.charAt(pt) == pattern.charAt(pp)) {
pt++;
pp++;
} else if(pp == 0) {
pt++;
} else {
pp = skip[pp];
}
}
if(pp == pattern.length()) {
// 패턴의 모든 문자 대조
return pt - pp;
} else {
// 검색 실패
return -1;
}
}
'프로그래밍👩🏻💻 > 알고리즘' 카테고리의 다른 글
[알고리즘/그래프] 너비 우선 탐색(Breath-first-search, BFS), 깊이 우선 탐색(Depth-first-search, DFS) (0) | 2022.07.31 |
---|---|
[알고리즘] 탐욕 알고리즘(Greedy Algorithm) (0) | 2022.07.25 |
[Algorithm/문자열 탐색] 보이어-무어(Boyer-Moore) 알고리즘 (0) | 2022.06.28 |
[Algorithm/문자열 탐색] 브루트-포스법(Brute force method) (0) | 2022.06.27 |
[Algorithm] 도수/계수 정렬(Counting Sort) (0) | 2022.06.26 |
Comments