테마 선택

📚 지식 노트

AI·하드웨어·주변기기·게임·컴퓨터 시스템·이론 컴퓨터 과학·수학·개발과 운영·보안·응용 분야에 대해 알아 두면 좋은 내용을 정리한 노트다. 위에서 분야를 고르고 아래에서 노트를 고른다.

문자열 문제

개념마다 확인(뜻을 맞게 알았나) → 추적(손으로 한 단계씩) → 응용(처음 보는 상황) 순서로 푼다. 풀이 보기를 누르기 전에 종이에 먼저 적어 보자.

목차 (6)
  1. 단순 탐색
  2. KMP 실패 함수
  3. KMP
  4. 라빈-카프
  5. 편집 거리
  6. 접미사 배열

KMP 실패 함수

확인

패턴 ABCAB의 실패 함수 마지막 값 π[4]는 얼마인가? 또 ABCAB 전체가 자기 자신의 접두사이자 접미사인데, 왜 π[4]가 5가 아닌가?

패턴 ABCAB와 실패 함수 0, 0, 0, 1, 물음표패턴A0B1C2A3B4π00010213?4
물음표 칸을 채워 보라.
풀이 보기

π[4] = 2다. ABCAB의 앞 AB와 뒤 AB가 같고, 세 글자(ABC와 CAB)는 다르다.

ABCAB의 실패 함수 0, 0, 0, 1, 2. 앞의 AB와 뒤의 AB가 같다패턴A0B1C2A3B4π0001021324
앞 두 글자와 끝 두 글자가 겹친다.

실패 함수는 진부분 문자열(자기 자신 전체는 뺀다)만 센다. π가 맞춘 길이 j와 같으면 틀렸을 때 패턴을 j − π = 0칸 밀게 되어 같은 비교를 끝없이 반복한다. 진부분으로 제한해야 틀릴 때마다 패턴이 적어도 한 칸 나아간다.

추적

패턴 ABACABAB의 실패 함수 표를 처음부터 끝까지 구하라. 마지막 칸을 채울 때 k가 어떻게 바뀌는지도 적어 보라.

패턴 ABACABAB와 비어 있는 실패 함수 표패턴A0B1A2C3A4B5A6B7π00?1?2?3?4?5?6?7
채울 표. π[0]은 늘 0이다.
풀이 보기

π = [0, 0, 1, 0, 1, 2, 3, 2]다.

ABACABAB의 실패 함수 0, 0, 1, 0, 1, 2, 3, 2패턴A0B1A2C3A4B5A6B7π0001120314253627
ABACABAB의 실패 함수. 마지막 칸은 k가 3에서 1로 물러난 뒤 2가 된다.

i = 6까지는 앞에서 이어진다(ABA까지 맞아 k = 3). i = 7에서 p[7] = B와 p[3] = C가 달라 k를 π[2] = 1로 물린다. 이번에는 p[7] = B와 p[1] = B가 같아 k = 2가 되고, π[7] = 2다. 실제로 ABACABAB의 끝 AB가 앞 AB와 같고, 끝 ABAB는 앞 ABAC와 다르다.

응용

실패 함수로 문자열이 더 짧은 단위의 반복인지 알 수 있다. ABCABCABC와 ABCABCAB는 각각 어떤 단위의 반복인가? 실패 함수 마지막 값만으로 답하라.

ABCABCABC의 실패 함수 0, 0, 0, 1, 2, 3, 4, 5, 6과 ABCABCAB의 실패 함수 0, 0, 0, 1, 2, 3, 4, 5ABCABCABCA0B1C2A3B4C5A6B7C8π000102132435465768ABCABCABA0B1C2A3B4C5A6B7π0001021324354657
두 문자열과 실패 함수.
풀이 보기

ABCABCABC는 ABC의 세 번 반복이고, ABCABCAB는 어떤 짧은 단위의 정확한 반복도 아니다. 가장 짧은 주기는 m − π[m − 1]이다. 첫 문자열은 9 − 6 = 3이고 9가 3으로 나누어떨어지므로 ABC × 3이다.

둘째는 8 − 5 = 3으로 주기는 3이지만(세 칸 밀면 겹친다) 8이 3으로 나누어떨어지지 않아 ABC를 몇 번 이어 붙여도 정확히 만들어지지 않는다. 그래서 반복 단위는 문자열 자신(길이 8)이다. 주기 m − π[m − 1]이 m을 나눌 때만 반복이다.

라빈-카프

확인

숫자열의 해시를 "십진수로 읽어 11로 나눈 나머지"로 정한다. 패턴 26의 해시는 4다. 다음 두 말은 각각 참인가? ① 창의 해시가 4가 아니면 그 창은 26이 아니다. ② 창의 해시가 4이면 그 창은 26이다.

26, 15, 37은 11로 나눈 나머지가 모두 4다26 mod 11 = 42615 mod 11 = 41537 mod 11 = 437
해시가 모두 4인 세 수.
풀이 보기

①은 참, ②는 거짓이다. 같은 글자열은 늘 같은 해시를 내므로 해시가 다르면 글자도 반드시 다르다. 그래서 해시가 다른 창은 글자를 보지 않고 넘긴다. 반대로 15, 37처럼 다른 수도 같은 나머지를 낼 수 있다(가짜 일치).

그래서 라빈-카프는 해시가 같을 때 반드시 글자를 직접 비교한다. 해시는 "다르다"를 빨리 판정하는 거름망이지 "같다"의 증거가 아니다.

추적

숫자열 31415926535에서 패턴 26을 라빈-카프로 찾는다(해시 = 십진수 mod 11). 창마다의 해시를 구하고, 가짜 일치가 몇 번 나오는지 세어 보라.

숫자열 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5본문30114213549526675839510
본문 숫자열. 길이 2짜리 창이 열 개 나온다.
풀이 보기

창 해시는 9, 3, 8, 4, 4, 4, 4, 10, 9, 2이고, 가짜 일치는 3번(15, 59, 92)이다. 진짜 일치는 6번 자리의 26 하나다. 해시가 4인 창 네 개에서만 글자를 비교한다.

라빈-카프 단계 그림: 31415926535에서 26을 찾는다. 3, 4, 5번 자리는 해시만 같은 가짜 일치이고 6번 자리가 진짜 일치다패턴 26: 해시 = 26 mod 11 = 4본문창 해시03112431455962768593105창 31: 해시 9해시가 달라 건너뜀창 14: 해시 3해시가 달라 건너뜀창 41: 해시 8해시가 달라 건너뜀창 15: 해시 4해시만 같음: 가짜 일치창 59: 해시 4해시만 같음: 가짜 일치창 92: 해시 4해시만 같음: 가짜 일치창 26: 해시 4해시도 글자도 같음: 찾음창 65: 해시 10해시가 달라 건너뜀창 53: 해시 9해시가 달라 건너뜀창 35: 해시 2해시가 달라 건너뜀93844441092갱신: 새 해시 = ((옛 해시 − 나가는 숫자 × 10) × 10 + 들어오는 숫자) mod 11지금 창0가짜 일치0진짜 일치(창 시작 칸 아래에 해시를 적는다)
1 / 10

첫 창 31의 해시를 직접 계산한다. 9 ≠ 4: 글자를 보지 않고 넘어간다.

31415926535에서 26 찾기(법 11). 법이 작아 해시가 겹치기 쉬워 가짜 일치가 세 번 나온다.

법이 11이면 해시 값이 11가지뿐이라 열 창 중 넷이 같은 값에 몰렸다. 실무에서 10⁹ 근처의 큰 소수를 법으로 쓰는 이유다.

응용

같은 숫자열에서 길이 3 창을 쓴다(법 11). 창 141의 해시는 9다. 141을 다시 읽지 않고, 나가는 숫자 1과 들어오는 숫자 5만으로 다음 창 415의 해시를 구하라.

숫자열에서 창 141(1~3번)이 창 415(2~4번)로 한 칸 밀린다창 14130114213549526675839510창 41530114213549526675839510
창을 한 칸 민다. 위가 지금 창, 아래가 다음 창이다.
풀이 보기

해시는 8이다. 나가는 숫자의 자릿값은 10² mod 11 = 1이다. 새 해시 = ((9 − 1 × 1) × 10 + 5) mod 11 = 85 mod 11 = 8. 직접 계산한 415 mod 11 = 8과 같다.

뺄셈이 음수가 되면 법을 한 번 더해 양수로 맞춘다. 10² mod 11은 창 길이가 정해지면 한 번만 구해 두므로, 창 길이가 m이어도 한 칸 미는 비용은 곱셈·덧셈 몇 번인 O(1)이다. 다시 계산하면 O(m)이다.

편집 거리

확인

CAT을 CART로 바꾸는 편집 거리는 얼마인가? 표에서 답은 어느 칸이고, D[2][0]은 무슨 뜻이며 값은 얼마인가?

CAT과 CART바꿀 글C0A1T2목표C0A1R2T3
두 문자열. 행은 CAT의 앞 i글자, 열은 CART의 앞 j글자다.
풀이 보기

편집 거리는 1(R 넣기)이고, 답은 오른쪽 아래 D[3][4]다. D[2][0]은 CA를 빈 문자열로 바꾸는 비용이라 두 글자를 지우는 2다. 0행·0열이 0, 1, 2…로 시작하는 까닭이다.

편집 거리 단계 그림: CAT과 CART의 표. 오른쪽 아래가 1이고, 되짚으면 R 하나를 넣는다εCARTεCAT0123401234101230123410123210120123410123210123211101234101232101232111편집 1번R 넣기↖ 대각선 + 0/1(같으면 0, 다르면 바꾸기)↑ 위 + 1: 지우기← 왼쪽 + 1: 넣기방금 채운 줄되짚은 경로아직 비어 있음
1 / 5

0행과 0열은 빈 문자열에서 만들거나 빈 문자열로 지우는 비용이라 0부터 1씩 늘려 채운다.

CAT → CART의 편집 거리 표. 되짚은 경로가 대각선으로 내려가다 한 번 오른쪽(넣기)으로 간다.

추적

HORSE를 ROS로 바꾸는 편집 거리 표를 채워라. 거리는 얼마이고, 표를 되짚으면 어떤 편집이 나오는가?

HORSE와 ROS바꿀 글H0O1R2S3E4목표R0O1S2
두 문자열.
풀이 보기

편집 거리는 3이다. 표의 마지막 줄은 [5, 4, 4, 3]이다. 되짚으면 H → R 바꾸기, R 지우기, E 지우기가 나온다(O와 S는 그대로 둔다).

편집 거리 단계 그림: HORSE와 ROS의 표를 한 줄씩 채우면 오른쪽 아래가 3이다. 되짚으면 H를 R로 바꾸고 R과 E를 지운다εROSεHORSE012301231123012311232212012311232212322201231123221232224332012311232212322243325443012311232212322243325443편집 3번H → R 바꾸기R 지우기E 지우기↖ 대각선 + 0/1(같으면 0, 다르면 바꾸기)↑ 위 + 1: 지우기← 왼쪽 + 1: 넣기방금 채운 줄되짚은 경로아직 비어 있음
1 / 7

0행과 0열은 빈 문자열에서 만들거나 빈 문자열로 지우는 비용이라 0부터 1씩 늘려 채운다.

HORSE → ROS의 편집 거리 표. 한 줄씩 채우고 마지막 단계에서 경로를 되짚는다.

표를 되짚을 때 대각선·위·왼쪽 중 같은 값으로 이어지는 이웃이 둘 이상이면 어느 쪽을 먼저 보느냐에 따라 다른 편집 순서가 나올 수 있다. 그래도 비용은 모두 3이다. 거리 값은 하나지만 최적의 편집은 여러 개일 수 있다.

응용

맞춤법 검사기가 오타 TEH에 대해 THE와 TEA 중 하나를 추천한다. 레벤슈타인 거리로 고르면 무엇을 추천하는가? 사람이 원했을 단어와 다르다면 무엇을 바꿔야 하는가?

오타 TEH와 후보 THE, TEA오타T0E1H2후보 1T0H1E2후보 2T0E1A2
오타와 두 후보.
풀이 보기

TEH → THE는 2, TEH → TEA는 1이라 TEA를 추천한다. 레벤슈타인 거리에는 맞바꾸기가 없어서 두 글자가 뒤바뀐 오타(EH ↔ HE)를 바꾸기 두 번으로 센다.

편집 거리 단계 그림: TEH와 THE의 표. 오른쪽 아래가 2이고, 되짚으면 E를 H로, H를 E로 바꾼다εTHEεTEH01230123101201231012211101231012211132120123101221113212편집 2번E → H 바꾸기H → E 바꾸기↖ 대각선 + 0/1(같으면 0, 다르면 바꾸기)↑ 위 + 1: 지우기← 왼쪽 + 1: 넣기방금 채운 줄되짚은 경로아직 비어 있음
1 / 5

0행과 0열은 빈 문자열에서 만들거나 빈 문자열로 지우는 비용이라 0부터 1씩 늘려 채운다.

TEH → THE의 편집 거리 표. 맞바꾸기가 없어 바꾸기 두 번이 든다.

이웃한 두 글자 맞바꾸기도 비용 1로 치는 다메라우-레벤슈타인 거리를 쓰면 TEH → THE도 1이 되어 두 후보가 같아진다. 그다음은 단어가 얼마나 자주 쓰이는지(빈도)로 THE를 고른다. 실제 검사기는 거리와 빈도, 자판에서 가까운 글자 같은 정보를 함께 쓴다.

접미사 배열

확인

banana의 접미사 배열은 [5, 3, 1, 0, 4, 2]다. na로 시작하는 접미사는 몇 번째 순위에 있고, na는 본문 어디에서 나오는가? 왜 그런 접미사들은 늘 이웃해 있는가?

banana와 그 접미사 배열 5, 3, 1, 0, 4, 2본문b0a1n2a3n4a5SA503112034425
banana와 접미사 배열(SA). SA의 칸 아래 숫자가 순위다.
풀이 보기

순위 4와 5(na, nana)이고, na는 2번과 4번 위치에서 나온다. 사전순 정렬은 첫 글자부터 비교하므로, 앞 두 글자가 na인 문자열은 na보다 작은 것과 큰 것 사이의 한 구간에 모인다.

banana의 접미사 배열에서 na로 시작하는 접미사 na와 nana가 순위 4와 5에 이웃해 있다순위SA(시작 위치)접미사(사전순)LCP05a013ana121anana330banana044na052nana2"na" 찾기이진 탐색으로순위 4~5→ 위치 2, 4LCP: 바로 윗줄과 앞부분이 같은 글자 수. 같은 접두사끼리 이웃에 모인다찾는 패턴과 겹친 앞부분윗줄과 같은 앞부분(LCP)
banana의 접미사 배열에서 na로 시작하는 구간.

추적

papaya의 접미사를 모두 적고 사전순으로 정렬해 접미사 배열과 LCP 배열을 구하라. 그다음 pa가 나오는 위치를 이진 탐색으로 찾아라.

본문 papaya본문p0a1p2a3y4a5
본문. 접미사는 위치 0~5에서 시작하는 여섯 개다.
풀이 보기

SA = [5, 1, 3, 0, 2, 4], LCP = [0, 1, 1, 0, 2, 0]이고, pa는 순위 3~4로 위치 0과 2에서 나온다. 사전순은 a, apaya, aya, papaya, paya, ya다.

papaya의 접미사 배열 5, 1, 3, 0, 2, 4. pa로 시작하는 papaya와 paya가 순위 3과 4에 있다순위SA(시작 위치)접미사(사전순)LCP05a011apaya123aya130papaya042paya254ya0"pa" 찾기이진 탐색으로순위 3~4→ 위치 0, 2LCP: 바로 윗줄과 앞부분이 같은 글자 수. 같은 접두사끼리 이웃에 모인다찾는 패턴과 겹친 앞부분윗줄과 같은 앞부분(LCP)
papaya의 접미사 배열. 굵은 테두리가 pa로 시작하는 구간이다.

apaya와 aya는 a만 같아 LCP 1, papaya와 paya는 pa가 같아 LCP 2다. 이진 탐색은 "앞 두 글자가 pa 이상인 첫 순위"(3)와 "pa보다 큰 첫 순위"(5)를 찾아 그 사이를 답으로 낸다.

응용

mamama에서 두 번 이상 나오는 가장 긴 부분 문자열과, 서로 다른 (빈 문자열이 아닌) 부분 문자열의 개수를 접미사 배열과 LCP 배열로 구하라.

본문 mamama본문m0a1m2a3m4a5
본문.
풀이 보기

가장 긴 반복은 mama(LCP 최댓값 4)이고, 서로 다른 부분 문자열은 11개다. 두 번 이상 나오는 부분 문자열은 두 접미사의 공통 접두사이고, 가장 긴 공통 접두사는 정렬에서 이웃한 쌍에 있으므로 LCP의 최댓값이 답이다.

mamama의 접미사 배열 5, 3, 1, 4, 2, 0과 LCP 0, 1, 3, 0, 2, 4. mama로 시작하는 접미사가 위치 0과 2에서 나온다순위SA(시작 위치)접미사(사전순)LCP05a013ama121amama334ma042mama250mamama4"mama" 찾기이진 탐색으로순위 4~5→ 위치 0, 2LCP: 바로 윗줄과 앞부분이 같은 글자 수. 같은 접두사끼리 이웃에 모인다찾는 패턴과 겹친 앞부분윗줄과 같은 앞부분(LCP)
mamama의 접미사 배열. LCP 4인 mama와 mamama가 이웃해 있다.

부분 문자열은 모두 어떤 접미사의 접두사다. 접미사 길이의 합 n(n + 1)/2 = 21개 중, 바로 윗줄과 겹치는 접두사(LCP)는 이미 센 것이므로 뺀다. LCP 합은 0 + 1 + 3 + 0 + 2 + 4 = 10이라 21 − 10 = 11이다. mama는 위치 0과 2에서 서로 겹쳐 나온다.