본문 바로가기

알고리즘

Z 알고리즘

Z 알고리즘이란 문자열 관련 알고리즘으로, Z array를 채우는 알고리즘이다. 길이 $N$의 문자열 $S$가 주어졌을 때 Z array는 아래와 같이 정의된다.

$Z[i]:=S$와 $S[i, N - 1]$에 대해 longest common prefix의 길이

이를 $O(N)$에 구할 수 있다.

 

알고리즘은 KMP와 SA의 중간 정도 느낌이다.

$i=1, ..., N-1$에 대해 $Z[i]$를 차례로 구할 것이다. 이때 이전까지 구한 $Z[i]$에 대해, $i+Z[i]$가 최대인 경우의 양 끝점을 기억해두자. ($L=i, R=i+Z[i]-1$)

i) $R < i$

그냥 naive하게 계산하자. 이후 $L$과 $R$ 갱신.

ii) $i \le R$

자명하게 $L < i$이다. $S[0, R - L]$과 $S[L, R]$이 일치한다는 점을 이용하자. $Z[i-L]\le R-i$이면 $Z[i]=Z[i-L]$이다. 만약 $Z[i-L]>R-i$이면 $Z[i]\ge R-i+1$이고, 여기서부터는 naive하게 계산해주면 된다. (이후 $L, R$도 갱신하기)

총 계산량이 $R$의 값이 증가한 양과 같기 때문에 $O(N)$이다.

 

아래 링크를 통해 공부하였다.

https://sgc109.tistory.com/208

 

아래는 코드이다.

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100010;

int N;
char S[MAXN];
int z[MAXN];

void get_z() {
	z[0] = N;	// 그냥 의미상 N
	int L = 0, R = 0;
	for(int i = 1; i < N; i++) {
		if(R < i) {
			for(z[i] = 0; S[z[i]] == S[i + z[i]]; z[i]++);
			L = i;
			R = i + z[i] - 1;
		}
		else {
			if(z[i - L] <= R - i) z[i] = z[i - L];
			else {
				for(z[i] = R - i + 1; S[z[i]] == S[i + z[i]]; z[i]++);
				L = i;
				R = i + z[i] - 1;
			}
		}
	}
}

 

'알고리즘' 카테고리의 다른 글

FWHT (Fast Walsh-Hadamard Transform)  (1) 2021.10.05
아호코라식 (Aho-Corasick)  (0) 2021.08.21
MCMF (Minimum Cost Maximum Flow)  (0) 2021.06.23
SPFA (Shortest Path Faster Algorithm)  (0) 2021.06.23
FFT (Fast Fourier Transform)  (0) 2021.04.03