Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 백준
- DP
- BOJ
- Math
- 따라하면서 배우는 C언어
- dfs
- 따라하며 배우는 C언어
- programmers
- C언어
- Algorithm
- server
- JavaScript
- 따배씨
- 생활코딩
- graph
- BASIC
- udemy
- 인프런
- greedy
- 종만북
- Python
- C
- 정수론
- Cleancode
- php
- sorting
- Algospot
- web
- BFS
- String
Archives
- Today
- Total
몽상실현개발주의
[종만북] 문자열 검색 - KMP 알고리즘 / 문자열 본문
[종만북] 문자열 검색 - KMP 알고리즘 / 문자열
문자열 검색 - KMP 알고리즘
단순한 알고리즘의 검색 과정에서 얻는정보를 이용하여 시간을 절약 할 수 있다.
H 의 부분 문자열을 N 과 비교 시, N 의 첫 글자와 대응 되지 않는 H 의 부분문자열 위치를 시작 위치 후보들에서 제외 시키는 방법으로 구현하면 최적화가 가능하다.
이와 같은 방법은 커누스-모리스-프랫(Knuth-Morris-Pratt) 알고리즘이며, 흔히 KMP 알고리즘으로 부른다.
- H[i...i+matched-1] = N[...matched-1](접두사) 이 일치 할때,
- i < i+k < matched-1,
- H[i+k...i+matched-1] = N[K...] (접미사) 가 일치 한다면,
- N[K...] (접미사) = N[...matched-1] (접두사) 구간이 존재
- N의 접미사 구간과 접두사 구간이 같은 문자열인 경우
- 이를 이용하기 위하여 N의 각 접두사에 대해 접두사도 되고 접미사도 되는 문자열의 최대 길이를 계산해 둔다.
-
pi[i] =N[...i]의 접두사도되고접미사도되는문자열의 최대 길이
- 부분 일치 테이블
-
- 정리
- i+k 시작점에서 일치 시, N[...matched-1] 의 문자열에서 길이가 matched-k 인" 접두사 = 접미사" 구간이 존재 해야함.
- N의 각 접두사에 대해 "접두사 = 접미사" 최대 길이를 계산해두고 이 길이만 비교하여 최적화 가능
- pi[i] = N[...i] 의 "접두사 = 접미사" 문자열 최대 길이
- pi[i] 를 이용하여 다음 시작위치를 계산
- i < i+k < matched-1,
KMP 알고리즘 구현
// KMP 문자열 검색 알고리즘의 구현
// H 의 부분 문자열로 N 이 출현하는 시작 위치들을 모두 반환
vector <int> kmpSearch(const string& H, const string& N){
int h_length = H.size()
int n_length = N.size();
vertor<int> ret;
// pi[i] = N[...i] 의 접미사도 되고 접두사도 되는 문자열의 최대 길이
vector<int> pi = getPartialMatch(h_length);
// begin = matched = 0 에서부터 시작
int begin = 0;
int matched = 0;
while(begin <= h_length - n_length){
// H 의 해당 글자가 N 의 해당 글자와 같다면
if(matched < m && H[begin + matched] == N[matched]){
++matched;
// n_length 개의 글자가 모두 일치하면 답에 추가.
if(matched == n_length) ret.push_back(begin);
} else {
// 예외: matched 가 0 인 경우, 다음칸에서 시작
if(matched == 0){
++begin;
} else {
begin += matched - pi[matched-1];
// begin 을 옮겻다고 처음부터 비교할 필요가 없다.
// 옮긴 후에도 pi[matched-1] 만큼은 항상 일치 하기 때문
matched = pi[matched-1];
}
}
}
return ret;
{
- 시작위치 0 에서부터 H 와 N 의 글자를 비교
- matched 글자가 일치한 후 불일치가 발생한 경우, 시작위치를 matched-pi[matched-1] 만큼 증가
- pi[i] = N[...i] 의 "접두사 = 접미사" 문자열의 최대 길이
- pi[] 는 N 이 어디까지 일치했는지가 주어질 때, 다음 시작 위치를 알려주기 때문에 부분 일치 테이블 (Partial match table) 이라고 한다.
시간 복잡도 분석
- while문 내에서 begin + matched 의 값은 절대 감소하지 않음
- matched 가 감소할 때에도 begin은 항상 감소분만큼 증가하기 때문에, begin+matched 는 불변
- 문자 비교 분기
- 문자 비교 성공 - H 의 각 문자당 최대 한 번씩만 발생 가능 -> 최대 O(|H|) 번 수행
- 문자 비교 실패 - 0 <= begin <= |H| - |N|, 분기당 1 씩 증가 -> 최대 O(|H|) 번 수행
- 전체 수행 회수: 최대 O(|H|) 번 수행, H 의 길이에 비례
부분 일치 테이블 구현
- 간단한 방법
- N 의 각 접두사에 대해 가능한 답을 하나씩 모두 시도
- |N| 개의 모든 접두사에 대해 O(|N| ^ 3) 의 수행
// N 에서 자기 자신을 찾으면서 나타나는 부분 일치를 이용하여 pi[] 를 계산
// p[i] = N[...i] 의 "접미사 = 접두사" 인 문자열의 최대 길이
vector<int> getPartialMatchNaive(const string& N){
int n_length = N.size()
vector<int> pi(n_length, 0);
// 단순한 문자열 검색 알고리즘 구현
for (int begin = 1; begin < n_length; ++begin){
for (int i = 0; i < m; ++i){
if(N[begin + i] != N[i]) break;
// i+1 글자가 서로 대응
pi[begin + i] = max( pi[begin + i] , i + 1 );
}
}
return pi;
}
- 최적화
- 각 접두사에 대해 pi[] 의 값을 모든 접두사에 대해 계산
- N[i] 와 N[begin + i] 가 일치할 때마다, pi[begin+i] 를 갱신
- |N| 개의 모든 접두사에 대해 O(|N| ^ 2) 의 수행
// KMP 알고리즘올 이용해 부분 일치 테이볼을 생성하기
// N에서 자기 자신을 찾으면서 나타나는 부분 일치를 이용해 pi[]를 계산
// pi[i] = N[...i] "접미사 = 접두사" 문자열의 최대 길이
vector<int> getPartiaLMatch(const string& N) {
int n_length = N.size();
vector<int> pi(n_length, 0);
// KMP 이용
// N을 N에서 찾는다. begin = 0 인 경우 자기자신을 찾는 경우라서 제외
int begin =1, matched =0;
// 비교할 문자가 N의 끝에 도달할 때까지 찾으면서 부분 일치를 모두 기록
while(begin + matched < n_length) {
if(N[begin + matched] == N[matched]) {
++matched;
pi[begin+matched-1] = matched;
} else {
if(matched == 0){
++begin;
} else {
begin += matched - pi[matched-1];
matched = pi[matched-1];
}
}
}
return pi;
}
- KMP 문자열 검색을 이용하기 때문에 시간복잡도는 O(|N|)
- 따라서, KMP를 이용한 부분 문자열 검색의 전체 시간복잡도는 O(INI +IHI)
'Language > Algorithm' 카테고리의 다른 글
[종만북] 문자열 검색 / 문자열 (0) | 2021.12.28 |
---|---|
[종만북] Queue, Stack, Deque / 큐와 스택, 데크 (0) | 2021.11.30 |
[종만북] 연결 리스트 / 선형 자료 구조 (0) | 2021.11.12 |
[종만북] 동적 배열 / 선형 자료 구조 (0) | 2021.11.10 |
[종만북] 모듈라 연산 / 정수론 (0) | 2021.10.09 |
Comments