Search
Duplicate
🔒

KMP 알고리즘

개요
대표적인 문자열 검색 알고리즘이다.
주요개념은 불일치가 발생하기 직전까지 같았던 부분은 다시 비교하지 않고 패턴 매칭을 진행하는 것이다.
비교 횟수를 줄이고 검색 알고리즘의 효율성을 높이는 것이 이 알고리즘의 의도이다.
구현
구현에 있어서 접두부접미부, 경계에 대한 의미를 알고 있어야 한다.
접두부 배열은 문자열의 왼쪽부터 시작하여 한 개씩 읽어가면서 만들고, 접미부 배열은 문자열의 마지막부터 시작하여 마찬가지로 한 개씩 읽어가면서 만든다.
경계접두부접미부가 같을 때, 그 접두부 또는 접미부를 경계라고 한다.
목적 문자열과 비교 문자열의 일치하는 패턴을 발견했을때, 해당 패턴의 길이 - 해당 패턴의 길이에서 최대 경계 값만큼 이동시켜 탐색하는 것이다.
그때 그때 구할 수 없으니 이는 이동경로 테이블을 만들어두고 사용한다.
코드
package string; public class KMP { public static void main(String[] args) { String s = "abacabacabacaabacabaac"; String p = "abacabaac"; int[] pi = getPi(p); int result = kmp(s, p, pi); System.out.println(result); } public static int[] getPi(String p) { // pi[i] : p[0] ~ p[i]까지의 부분 문자열 중에서 접두사 == 접미사의 최대 길이 int[] pi = new int[p.length() + 1]; pi[0] = -1; // j : 접두사 == 접미사의 최대 길이 int j = 0; // i : 접미사 포인터 for (int i = 1; i < p.length(); i++) { // j가 0보다 크고, 접두사와 접미사가 다르면 j를 pi[j-1]로 갱신 while (j > 0 && p.charAt(i) != p.charAt(j)) { j = pi[j]; } // 접두사와 접미사가 같으면 j를 증가시키고 pi[i]에 j를 저장 if (p.charAt(i) == p.charAt(j)) { pi[i + 1] = ++j; } } return pi; } public static int kmp(String s, String p, int[] pi) { int sLen = s.length(); int pLen = p.length(); int dist = 0; int idx = 0; int cnt = 0; while (true) { idx = 0; if ((idx + dist) + pLen > sLen) { break; } while (s.charAt(idx + dist) == p.charAt(cnt)) { idx++; cnt++; if (cnt == pLen) { return dist; } } dist = dist + (cnt - pi[cnt]); cnt = 0; } return 0; } }
Java
복사