해싱이란?
해싱(hashing) 은 임의의 데이터(문자열, 상태 등)를 고정 크기의 정수(해시값)
로 바꾸는 기법입니다. 긴 데이터를 짧은 숫자로 요약해, 비교와 검색을 매우 빠르게
만듭니다.
핵심 직관: 두 데이터의 해시값이 다르면 반드시 두 데이터가 다릅니다. 해시값이
같으면 "거의 확실히" 같습니다(드물게 충돌 가능). 그래서 무거운 비교를 가벼운
정수 비교로 대체할 수 있습니다.
1. 왜 빠른가
문자열 두 개를 직접 비교하면 길이에 비례해 \(O(L)\)이 듭니다. 하지만 미리 해시값을
구해 두면 정수 한 번 비교로 \(O(1)\) 에 끝납니다. 문자열을 수없이 비교하는
문제에서 이 차이는 결정적입니다.
집합·맵(unordered_set/map, 파이썬 set/dict)이 평균 \(O(1)\)인 것도 내부적으로
해싱을 쓰기 때문입니다.
2. 문자열 해싱: 다항식 해시
문자열을 다항식의 계수로 보고, 어떤 밑 \(p\)와 모듈러 \(m\)으로 값을 계산합니다.
$$ H(s) = (s_0 \cdot p^{0} + s_1 \cdot p^{1} + \cdots + s_{L-1} \cdot p^{L-1}) \bmod m $$
이렇게 하면 각 문자의 위치 정보가 해시값에 반영되어, 서로 다른 문자열이 같은
값을 가질 확률이 매우 낮아집니다. \(p\)는 보통 알파벳 크기보다 큰 소수(31, 53,
\(10^9+7\) 근방), \(m\)은 큰 소수를 씁니다.
3. 부분 문자열 해시를 O(1)에
다항식 해시의 진짜 위력은 누적 해시(prefix hash) 와 결합할 때입니다. 누적
해시를 미리 구해 두면, 임의 부분 문자열의 해시를 \(O(1)\) 에 꺼낼 수 있습니다.
이로써 "두 부분 문자열이 같은가?"를 \(O(1)\)에 판정할 수 있어, KMP 같은 전용
알고리즘 없이도 문자열 매칭·중복 탐지·회문 검사를 풀 수 있습니다. 이것을
라빈-카프(Rabin-Karp) 스타일이라 부릅니다.
4. 충돌과 그 대처
서로 다른 데이터가 같은 해시값을 갖는 것을 충돌(collision) 이라 합니다.
완벽히 피할 수는 없지만 확률을 낮출 수 있습니다.
- 큰 모듈러 — \(m\)이 클수록 충돌 확률 \(\approx 1/m\)로 낮아집니다.
- 이중 해시(double hashing) — 서로 다른 \((p, m)\) 쌍으로 두 해시를 함께 쓰면,
둘 다 충돌할 확률이 사실상 \(0\)이 됩니다. 경쟁에서 안전을 위해 자주 씁니다. - 저격(anti-hash) — 밑/모듈러가 알려지면 의도적 충돌 입력이 가능. 무작위 밑을
쓰면 방어됩니다.
5. 대표 활용
| 문제 | 해싱의 역할 |
|---|---|
| 문자열 매칭 | 부분 문자열 해시 비교 |
| 중복 부분 문자열 탐지 | 해시 집합 |
| 회문 판정 | 정방향·역방향 해시 비교 |
| 빠른 집합/맵 | 키를 해시 버킷에 분배 |
정리
해싱은 데이터를 정수로 요약해 비교·검색을 \(O(1)\)로 만듭니다. 문자열은 다항식
해시 + 누적 해시로 부분 문자열 비교를 \(O(1)\)에 처리하고, 충돌은 큰 모듈러와
이중 해시로 방어합니다. 다음 강의에서 구현합니다.