지난 학기 학교 알고리즘 수업을 수강하며, 정리 해 놓았던 마크다운 문서입니다. 문제시 삭제하겠습니다
Pattern matching이라고도 부름
string=characters의 나열
alphabet Σ =스트링 구성하는 문자집합 의미
하나의 스트링을 P라고 정의하고, 그 사이즈를 m이라 정의하자
substring(부분문자열)-임의의 인덱스 i부터 j까지 연속된 char의미
prefix(접두사)-substring of p[0..i]
suffix(접미사)-substring of p[i.. m-1]
Example
응용분야-텍스트 에디터, 검색 엔진, 생물학 연구
단순하게 모든 경우에 대해 수행하기
Algorithm BruteForceMatch(T, P)
Input text T of size n and pattern
P of size m
Output starting index of a substring of T equal to P
or -1 if no such substring exists
for i <- 0 to n - m{ test shift i of the pattern } //n-m까지 탐색진행, i=text상 인덱스
j <- 0 //j=pattern상의 인덱스
while j < m and T[i + j] = P[j]
j <- j + 1
if j = m
return i {match at i}
return -1 {no match anywhere}
브루트 포스 알고리즘에 비해 더 shift 할 수 없을까?
지금까지 match 되었던 prefix안에서 일치하는 최장 proper prefix 정보와 proper suffix정보 이용
즉 패턴 내에서 가장 일치하는 proper prefix, proper suffix 정보는 ab, 이정보를 가지고 패턴을 멀리 shift할것
proper prefix(ab)와 text상의 ab를 align 시킴
패턴 preprocessing 하는 failure func먼저 계산해주어야함
첫번째 의미: 패턴의 index를 j라 했을때 j까지 prefix내에서 일치하는 가장 긴 prefix와 proper suffix의 길이를 저장 (길이 m인 array 하나로 계산가능 O(m))
두번째 의미: 다음에 비교할 pattern의 index를 의미 (단, index가 0 based일때)
지금까지 match된 정보를 가지고 failure func이용
정리: j=0에서 mismatch 발생한경우 brute-force,
j>0이면 failure func 이용
Algorithm KMPMatch(T, P)
F <- failureFunction(P) // O(m) time
i <- 0 // text의 인덱스
j <- 0 // pattern의 인덱스
while i < n
//match 부분
if T[i] = P[j]
if j = m - 1
return i - j { match }
i <- i + 1
j <- j + 1
//
//mismatch 부분
else if j > 0
j <- F[j - 1] // failure func이용
else //j=0일때 (브루트 포스)
i <- i + 1
//
return -1 { no match }
Algorithm failureFunction(P) // O(m) time에 계산 가능
F[0] <- 0
i <- 1
j <- 0
while i < m
if P[i] = P[j]
{we have matched j + 1 chars}
F[i] <- j + 1
i <- i + 1
j <- j + 1
else if j > 0
{use failure function to shift P}
j <- F[j - 1]
else
F[i] <- 0 { no match }
i <- i + 1
19번의 비교연산으로 탐색 완료
두가지 Heuristics 전략 사용 알고리즘
Heuristics-어떤 알고리즘이 Heuristics이라 하는것은 최적해를 찾는것인데 그중에서 global optimal solution이 있고, local optimal solution이 있음
global optimal solution은 전체 input에 대해 최적해를 찾는것이고, local optimal solution은 전체적으로는 최적이 아닐수 있지만, 최적에 가까운 지역적으로는 최적의 solution 찾는 방법이 있음.
그중에 Heuristics 알고리즘은 global optimal solution 찾는데 굉장히 오랜시간 걸릴 수 있고 빠른시간에 local optimal solution 계산 보장하는 알고리즘 - Heuristics 알고리즘
(global opimal solution 보장하지 않지만 빠른시간에 global에 가까운 optimal solution 계산해줄수 있다.)
어떤 char가 존재하는지 존재하지 않는지 해당 char가 마지막에 발생 위치어디인지 미리 preprocessing 해줘야함 -> Last-occurrence function
Σ= {a, b, c, d}, P = abacab라면 그것에 대한 string은 a,b,c,d로만 이뤄져야함
Last-occurrence function의 크기->|Σ|=s
Last-occurrence function : O(m+s) time 에 수행가능(P사이즈: m, 시그마사이즈: s)
Algorithm BoyerMooreMatch(T, P, Σ)
L <- lastOccurenceFunction(P, Σ) // O(m+s) time
i <- m - 1 // 패턴의 가장 오른쪽 인덱스로 초기화, T의 인덱스
j <- m - 1 // P의 인덱스
repeat
//match 한경우
if T[i] = P[j]
if j = 0
return i { match at i }
else
i <- i - 1
j <- j - 1
//mismatch한 경우
else
{ character-jump }
l <- L[T[i]]
i <- i + m – min(j, 1 +l) // 두가지 케이스 포함한 수식 : j=case 1, 1+l=case 2
j <- m - 1 // lookiing-glass 사용하기 위해 항상 P마지막 위치로 업데이트
until i > n - 1
return -1 { no match }
mismatch 발생한 경우 두가지 케이스로 구분가능
주의 해야할 점: 패턴을 이동한다는것은 실제로는 text의 인덱스 i를 증가 시켜줘야함
위 예시에서 i를 어떻게 증가시키는가?
KMP 알고리즘에 비해 더 빠르게 수행가능
Boyer-Moore 알고리즘 수행시간 : O(nm+s)
T=aaa..aa
P=baaa (항상 매치하다가 마지막에 미스매치 발생하는 경우)
이런경우 계속 브루트 포스 알고리즘과 똑같이 수행 -> O(nm) time 에 수행
worst case의 경우 english text의 경우 거의 발생 x
따라서 Boyer-Moore 알고리즘은 worst case에 대한 수행시간은 느리지만, average case에서는 상당히 빠른 수행시간을 가짐