ONE QUESTION AT A TIME.

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

TODAY’S QUESTION93 / 1500

긴 텍스트에서 길이 K의 모든 부분 문자열 hash를 한 번씩 갱신할 때 어떤 항을 빼고 더하나요?

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

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

구두 답변

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

왼쪽 문자를 높은 자리로 두는 길이 K 다항식 hash를 c0*p^(K-1)+...+c(K-1)로 정하면, 한 칸 이동할 때 세 단계가 필요합니다. 먼저 오래된 c0의 기여 c0*p^(K-1)를 현재 hash에서 뺍니다. 그러면 남은 c1...c(K-1)이 한 자리씩 왼쪽으로 올라가야 하므로 base p를 곱하고, 마지막에 새 문자 cK를 더합니다. 따라서 next=((current-c0*highPower)*p+cK) mod m, highPower=p^(K-1) mod m입니다. 항을 빼지 않으면 이전 문자가 남고, 이동을 하지 않으면 자릿값이 달라집니다.

p=3, m=101, a=1,b=2,c=3,d=4로 abc→bcd를 추적하면 현재 값은 1*9+2*3+3=18입니다. a의 항 9를 빼 9, 남은 값을 3배 해 27, 새 d=4를 더해 31이 됩니다. 직접 계산한 2*9+3*3+4=31과 일치합니다. 코드에서는 빼기 뒤 음수 residue를 ((x%m)+m)%m처럼 정규화하고, c0*highPower와 곱셈이 고정 폭 정수를 넘지 않는지 확인해야 합니다.

이 식은 K가 고정된 스트리밍 창에 맞습니다. 임의 [l,r)를 자주 묻는 정적 텍스트라면 prefix hash와 power 배열이 더 자연스럽고, hash 일치 뒤 exact equality가 필요한지는 별도 계약입니다. K=0, K>text.length, 빈 텍스트는 window가 정의되지 않으므로 호출자가 오류·빈 결과 중 하나를 명시해야 합니다.

K=1이면 highPower=1이고 next=((current-c0)*p+c1) mod m이 되어 이전 문자를 제거한 뒤 새 문자만 남기는 형태가 됩니다. 반대로 K>text.length이면 첫 window 자체가 없으므로 음수 반복 횟수를 돌지 않게 입력을 거절해야 합니다. 모듈러를 매 단계 적용하면 값의 크기를 줄일 수 있지만, 언어의 곱셈 중간값이 이미 overflow할 수 있으므로 “마지막에만 %m”으로 충분하다고 보면 안 됩니다. 후보 hash 뒤 exact 비교가 필요하면 이 갱신식은 여전히 검색 필터일 뿐입니다.

02

득점 포인트

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

  • c0*p^(K-1)을 먼저 제거하고 남은 값을 p만큼 민다는 순서를 말합니다.
  • abc→bcd에서 18→9→27→31을 계산합니다.
  • highPower의 지수와 문자 방향을 명시합니다.
  • 음수 modulo와 overflow를 구현 경계로 제시합니다.
  • fixed window와 prefix hash의 저장·질의 차이를 구분합니다.
03

감점 포인트

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

  • 새 문자만 더하고 오래된 문자를 제거하지 않습니다.
  • p^(K-1) 대신 다른 거듭제곱으로 첫 항을 뺍니다.
  • 왼쪽이 높은 자리인지 낮은 자리인지 설명하지 않습니다.
  • 모든 언어의 %가 양수 residue를 준다고 가정합니다.
  • hash가 같으면 exact match라고 즉시 반환합니다.
04

더 파고들 거리

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

  • prefix hash와 rolling window를 메모리·임의 구간 질의·스트리밍 지연으로 비교해 보세요.
  • K=1에서 식이 어떻게 단순화되고 K=0은 왜 별도 API가 되는지 설명해 보세요.

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

← 전체 질문 보기