도구스개발

Z 알고리즘(문자열 검색) 계산기

문자열의 각 자리에서 맨 앞과 몇 글자나 겹치는지를 재는 Z 배열을 만들고, 값을 물려 쓰는 자리와 실제로 글자를 견주는 자리를 나눠 보여 줍니다. KMP 실패함수와의 관계, 그리고 구분자를 이어 붙여 검색하는 방법과 그 함정까지 다룹니다.

각 자리에서 맨 앞과 몇 글자나 겹치는지를 잽니다. 400자까지.

10자 · Z 배열

늘려 본 횟수 6번

이미 계산한 값을 2글자만큼 물려 썼습니다. 창을 쓰지 않고 한 글자씩 견주면 최악의 경우 45번까지 갑니다.

문자열 길이10자
늘려 본 횟수6번
물려 쓴 글자 수2자
가장 긴 겹침3자

Z 배열

i글자Z물려 씀늘림겹치는 부분
0a10자기 자신이라 뜻이 없다
1a11a
2b0
3x0
4a22aa
5a11a
6y0
7a33aab
8a11a
9b0

「물려 씀」이 있는 자리는 한 글자도 견주지 않고 값을 가져온 것입니다. 지금까지 본 것 중 가장 오른쪽까지 뻗은 일치 구간 안에 있으면, 그 구간이 이미 맨 앞과 같다는 것을 아니까 앞부분도 이미 계산해 둔 값과 같기 때문입니다. 「늘림」이 있는 자리에서만 실제로 글자를 견줍니다.

KMP 실패함수와 견주기

i글자Z[i]π[i]Z로 만든 π
0a1000
1a111
2b000
3x000
4a211
5a122
6y000
7a311
8a122
9b033

두 값이 재는 것이 다릅니다 — π[i]는 「s[0..i]의 접두사이면서 접미사인 가장 긴 길이」이고 Z[i]는 「s[i..]가 맨 앞과 겹치는 길이」입니다. 그런데 같은 사실을 다른 각도에서 본 것이라 서로를 만들어 낼 수 있습니다. 마지막 열은 Z 배열만으로 만든 실패함수인데 가운데 열과 완전히 같습니다.

검색에 써 보기

찾은 자리0, 7
찾은 개수2곳
쓴 구분자#
한 자리씩 견준 검색과같음

이어 붙인 문자열: aab#aabxaayaab

패턴 + 구분자 + 본문을 이어 붙여 Z 값이 패턴 길이와 같은 자리를 찾으면 그것이 곧 매칭입니다. 겹치는 매칭도 빠짐없이 나오고, 본문을 한 번만 훑으면 끝납니다.

구분자가 이 방법의 유일한 함정입니다. 패턴에도 본문에도 나오지 않는 글자여야 합니다. 그러지 않으면 일치가 구분자를 넘어 이어져 없는 매칭이 생기거나 있는 매칭이 어긋납니다. 여기서는 #, $, @, ~, | 순으로 겹치지 않는 것을 고르고, 그것도 다 쓰였으면 제어문자까지 내려갑니다. 직접 고른 구분자가 겹치면 계산을 하지 않고 이유를 알려 줍니다.
왜 문자열 길이에 비례하는가. 값을 물려 쓸 수 없어 한 글자씩 늘려 보는 경우에도, 늘린 만큼 창의 오른쪽 끝이 오른쪽으로 갑니다. 창은 왼쪽으로 되돌아가지 않으므로 「늘려 본 총 횟수」가 문자열 길이를 넘을 수 없습니다. 위 표에서 「늘림」 열의 합이 문자열 길이 안쪽인 것을 보면 됩니다 — aaaaaaaa처럼 반복이 심한 입력일수록 차이가 극적으로 벌어집니다.

사용 방법

  1. 1문자열을 넣으면 Z 배열이 자리마다 나옵니다.
  2. 2「물려 씀」 열에서 글자를 견주지 않고 값을 가져온 자리를 확인합니다.
  3. 3KMP 실패함수와 나란히 놓고 두 값이 무엇을 재는지 견줍니다.
  4. 4아래 「검색에 써 보기」에 찾을 문자열과 본문을 넣습니다.
  5. 5이어 붙인 문자열과 쓴 구분자를 확인합니다.

자주 묻는 질문

Z[i]는 문자열 s와 s[i..]가 앞에서부터 몇 글자나 같은지입니다. "aabxaayaab"에서 Z[7] = 3인 것은 7번째부터의 "aab"가 맨 앞의 "aab"와 세 글자 통째로 같다는 뜻입니다. Z[0]은 자기 자신이라 늘 전체 길이여서 뜻이 없습니다.

지금까지 본 것 중 가장 오른쪽까지 뻗은 일치 구간을 들고 다니며 값을 물려 쓰기 때문입니다. 새 자리가 그 구간 안에 있으면 이미 계산해 둔 값을 그대로 가져오면 되고, 글자를 실제로 견주는 것은 구간 밖으로 나갈 때뿐입니다. 늘린 만큼 구간의 오른쪽 끝이 오른쪽으로 가고 왼쪽으로 되돌아가지 않으므로, 늘려 본 총 횟수가 문자열 길이를 넘을 수 없습니다.

재는 것이 다릅니다. 실패함수 π[i]는 「s[0..i]의 접두사이면서 접미사인 가장 긴 길이」이고, Z[i]는 「s[i..]가 맨 앞과 겹치는 길이」입니다. 같은 사실을 다른 각도에서 본 것이라 서로를 만들어 낼 수 있으며, 이 도구는 Z 배열만으로 실패함수를 만들어 나란히 보여 줍니다.

패턴 + 구분자 + 본문을 이어 붙여 Z 배열을 만든 뒤, Z 값이 패턴 길이와 같은 자리를 찾으면 그것이 곧 매칭입니다. 본문을 한 번만 훑으면 끝나고 겹치는 매칭도 빠짐없이 나옵니다.

패턴과 본문이 이어 붙어 일치가 경계를 넘어가는 것을 막기 위해서입니다. 구분자는 패턴에도 본문에도 나오지 않는 글자여야 하며, 그러지 않으면 없는 매칭이 생기거나 있는 매칭이 어긋납니다. 이 도구는 겹치지 않는 글자를 자동으로 고르고, 직접 고른 구분자가 겹치면 계산하지 않고 이유를 알려 줍니다.

같은 글자나 같은 조각이 되풀이되는 입력에서 차이가 큽니다. "aaaaaaaa"처럼 반복이 심하면 한 글자씩 견주는 방법은 길이의 제곱에 가까운 비교가 필요한데, Z 알고리즘은 값을 물려 써서 거의 견주지 않습니다.

전송되지 않습니다. 모든 계산은 브라우저 안에서 이뤄지고, 입력값은 이 기기에만 남습니다.

알아두면 좋은 점

  • 창을 물려 쓰지 않고 한 글자씩 견주는 두 번째 구현을 두고 대조합니다. Z 알고리즘이 빠른 이유가 바로 그 물려 쓰기이므로, 물려 쓰지 않는 방법과 답이 같은지가 핵심 검사입니다. 예제 열한 가지와 무작위 문자열 300개에서 확인했습니다.
  • Z[i]가 실제로 맨 앞과 겹치는 길이인지도 문자열을 잘라 직접 견줘 검사합니다. 한 글자 더 가면 달라야 한다는 것(더 길게 겹칠 수 없다는 것)까지 함께 봅니다.
  • Z 배열에서 만든 KMP 실패함수를 dev/kmp-failure의 구현과 대조합니다. 두 값은 같은 사실을 다른 각도에서 재는 것이라 서로가 서로의 검산이 되며, 무작위 문자열 300개에서도 일치합니다.
  • 검색 결과는 무식하게 한 자리씩 견준 검색과 대조합니다. 겹치는 매칭까지 같은 목록이 나와야 하며, 화면에도 두 결과가 같은지 표시합니다.
  • 창이 왼쪽으로 되돌아가지 않는다는 것, 물려 쓴 값이 최종 값보다 크지 않다는 것도 테스트로 고정했습니다. 「늘려 본 총 횟수가 문자열 길이에 묶인다」는 논증의 근거입니다.
  • 구분자가 겹치는 입력은 계산하지 않고 이유를 답합니다. 잘못된 구분자로도 답이 나오는 것이 이 방법에서 가장 흔한 사고이기 때문입니다.
  • 문자열은 400자, 찾을 문자열은 80자까지 다룹니다. 표를 통째로 그리는 것이 목적이라 그보다 길면 화면이 읽히지 않습니다.

함께 보면 좋은 도구

마지막 검증: 2026년 9월 1일 · 결과는 참고용 추정치입니다.