ONE QUESTION AT A TIME.

천천히 생각하고, 분명하게.

TODAY’S QUESTION115 / 1500

접미사 배열에 새 패턴을 찾을 때 한 번의 이진 탐색으로 끝나지 않고 범위를 두 번 찾는 이유는 무엇인가요?

잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?

답변과 점검 포인트 펼치기답변 접기
01

구두 답변

정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.

한 번의 이진 탐색으로 “어떤 일치가 존재하는가”를 확인하는 것과, 패턴을 접두로 갖는 모든 접미사의 구간을 얻는 것은 다른 질의입니다. 접미사 배열에서 패턴 P를 접미사와 비교할 때 P보다 사전순으로 작은 마지막 위치 다음을 lower_bound로 잡고, P를 접두로 갖는 마지막 위치 다음을 upper_bound로 잡습니다. banana의 suffix array는 [5,3,1,0,4,2], 즉 a, ana, anana, banana, na, nana 순서입니다. P=ana이면 배열 인덱스 [1,3)의 ana, anana가 모두 후보이고 원문 offset은 SA[1]=3, SA[2]=1입니다. 따라서 개수는 3-1=2입니다.

비교기는 완전한 문자열 동일성과 접두 일치를 나눠야 합니다. 접미사 a는 ana를 다 읽기 전에 끝나므로 작은 쪽이고, anana는 처음 세 글자가 ana와 같으므로 일치 구간 안에 들어갑니다. 이 규칙을 숫자 배열의 비교처럼 뭉뚱그리면 upper 경계에서 anana를 빠뜨리기 쉽습니다. 빈 패턴을 모든 위치에 허용할지 거절할지도 API에서 먼저 고정합니다. 이 예에서는 빈 패턴을 오류로 둡니다.

구현할 때는 경계를 반열린 구간으로 통일하면 l=0, r=n에서 시작해 불변식 앞쪽은 조건 불만족, 뒤쪽은 조건 만족을 유지하기 쉽습니다. 다만 두 번째 경계의 조건은 “패턴보다 크다”가 아니라 “패턴을 접두로 갖지 않는다”여야 합니다. ana와 anana가 둘 다 match인 이유가 바로 이 차이입니다. 반환 순서가 검색 순위가 아니라 원문 위치 순서여야 한다면 [1,3)의 3,1을 별도 정렬해야 하며, 배열을 찾는 비용과 결과 정렬 비용을 섞어 말하면 안 됩니다.

02

득점 포인트

이해가 드러나는 지점을 확인해 보세요.

  • P의 접두 일치가 사전순 정렬에서 하나의 연속 구간을 만든다는 이유를 설명합니다.
  • banana에서 [1,3)과 원문 위치 {3,1}을 구별해 추적합니다.
  • 접미사가 패턴보다 짧을 때와 패턴을 모두 소비했을 때의 비교 결과를 각각 말합니다.
  • 두 경계의 탐색 비용을 단순 구현 기준 O(|P| log n)으로 제시합니다.
  • suffix-array 인덱스와 원문 시작 offset을 혼동하지 않습니다.
03

감점 포인트

놓치기 쉬운 조건과 오해를 짚어 보세요.

  • 첫 번째 일치 접미사를 찾으면 출현 횟수까지 안다고 말합니다.
  • SA의 인덱스 1, 2를 원문 위치 1, 2라고 해석합니다.
  • ana와 anana가 완전히 같은 문자열이라고 말합니다.
  • 빈 패턴과 접미사 끝 비교의 계약을 생략합니다.
  • LCP 배열이 있다는 이유만으로 두 경계가 자동으로 O(log n)이라고 단정합니다.
04

더 파고들 거리

하나 더 질문하며 이해의 범위를 넓혀 보세요.

  • 패턴의 실제 출현 위치를 오름차순으로 반환하려면 [l,r)의 offset을 어떤 비용으로 다시 정렬해야 하나요?
  • LCP를 이용해 이진 탐색에서 이미 비교한 접두 길이를 재사용하려면 비교기 상태를 어떻게 바꿔야 하나요?

득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.

← 전체 질문 보기