반응형
📌 KMP란?
KMP(Knuth-Morris-Pratt) 알고리즘은 부분 문자열 검색(substring search)을 위한 알고리즘으로, 시간 복잡도 **O(N + M)**으로 매우 효율적입니다.
KMP는 비교 중 매칭 실패 시 불필요한 반복을 피하기 위해 "접두사-접미사 일치 정보"를 사전에 계산하여 사용합니다.
🔍 KMP의 핵심 아이디어
- 문자열 haystack에서 needle을 찾는 문제
- 부분 일치가 발생했을 때, 앞으로 돌아가지 않고 재사용할 수 있는 패턴을 저장
- 이때 사용하는 것이 LPS 배열 (Longest Prefix Suffix)
🧠 LPS 배열이란?
LPS(Longest Prefix Suffix) 배열은 자기 자신 내에서 접두사와 접미사가 일치하는 최대 길이를 저장하는 배열입니다.
예시: needle = "a b c d a b d"
index: 0 1 2 3 4 5 6
char: a b c d a b d
LPS: 0 0 0 0 1 2 0
- LPS[5] = 2 → 앞에서 "ab"와 일치하는 접두사/접미사가 존재함
✅ KMP 알고리즘 구현 (TypeScript)
function computeLPS(pattern: string): number[] {
const lps = new Array(pattern.length).fill(0);
let length = 0;
let i = 1;
while (i < pattern.length) {
if (pattern[i] === pattern[length]) {
length++;
lps[i] = length;
i++;
} else {
if (length !== 0) {
length = lps[length - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
export function kmpSearch(haystack: string, needle: string): number {
if (needle === "") return 0;
const lps = computeLPS(needle);
let i = 0; // haystack pointer
let j = 0; // needle pointer
while (i < haystack.length) {
if (haystack[i] === needle[j]) {
i++;
j++;
}
if (j === needle.length) {
return i - j;
} else if (i < haystack.length && haystack[i] !== needle[j]) {
if (j !== 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
return -1;
}
📈 시간 및 공간 복잡도
항목 복잡도 설명
시간 복잡도 | O(N + M) | N: haystack 길이, M: needle 길이 |
공간 복잡도 | O(M) | LPS 배열 저장 |
✅ KMP의 장점
- 모든 케이스에서 최악의 경우에도 선형 시간 보장
- needle이 반복되는 경우에 유리함
- 보안, 컴파일러, 문자열 매칭 시스템에서 자주 사용됨
반응형