contents
๐ ์ฝ๋ฉ ํ ์คํธ๋ฅผ ์ํ ํด์ฑ(Hashing) ์๊ณ ๋ฆฌ์ฆ ๊ฐ์ด๋ & ์์
ํด์ฑ์ ์ฝ๋ฉ ํ
์คํธ๋ ์๊ณ ๋ฆฌ์ฆ ๋ฌธ์ ํ์ด์์ ๋งค์ฐ ์ค์ํ ์ฃผ์ ์
๋๋ค.
"๋น ๋ฅธ ์กฐํ", "์ค๋ณต ์ ๊ฑฐ", "๋น๋ ๊ณ์ฐ"๊ณผ ๊ฐ์ ๋ฌธ์ ํ์ด ํธ๋ฆญ์ ํต์ฌ์ ์์ต๋๋ค.
1. ํด์ฑ(Hashing) ์ด๋?
ํด์ฑ์ ์ ์, ๋ฌธ์์ด ๋ฑ ์ ๋ ฅ ๋ฐ์ดํฐ๋ฅผ **ํด์ ํจ์(Hash Function)**๋ฅผ ์ด์ฉํด ๊ณ ์ ํฌ๊ธฐ์ ํด์ ์ฝ๋๋ก ๋ณํํ์ฌ, ๋น ๋ฅธ ๊ฒ์/์ ์ฅ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๊ธฐ๋ฒ์ ๋๋ค.
- ํด์ ํจ์(Hash Function): ์ ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ๊ณ ์ ํฌ๊ธฐ(๋๊ฐ ์ ์)์ ํด์ ์ฝ๋๋ก ๋ณํ
- ํด์ ํ ์ด๋ธ/์ (Hash Table/Set): ํด์์ฝ๋๋ฅผ ์ธ๋ฑ์ค๋ก ์ฌ์ฉํ์ฌ ๊ฒ์ยท์ฝ์ ยท์ญ์ ํ๊ท O(1) ์ฑ๋ฅ
- ์ถฉ๋(Collision): ์๋ก ๋ค๋ฅธ ์
๋ ฅ์ด ๊ฐ์ ํด์์ฝ๋๋ฅผ ๊ฐ์ง ๋ ๋ฐ์
- ํด๊ฒฐ๋ฒ: ์ฒด์ด๋(Chaining), ์คํ ์ด๋๋ ์ฑ(Open Addressing) ๋ฑ
2. ์ฃผ์ ํด์ ์๋ฃ๊ตฌ์กฐ
a. HashMap / HashSet (Java), Dictionary (Python)
- ๋น ๋ฅธ ์ถ๊ฐ, ๊ฒ์, ์ญ์ ์ง์
- ๋น๋ ์นด์ดํธ, ์กด์ฌ ์ฌ๋ถ ์ฒดํฌ, ์ค๋ณต ์ฒ๋ฆฌ์ ํ์
Java ์์ โ ์ซ์ ๋น๋ ์นด์ดํธ
int[] arr = {3, 5, 4, 3, 4, 3};
Map<Integer, Integer> map = new HashMap<>();
for (int num : arr)
map.put(num, map.getOrDefault(num, 0) + 1);
if (map.containsKey(5)) { /* ์กด์ฌ ์ฌ๋ถ ํ์ธ */ }
Java ์์ โ ์กด์ฌ ์ฌ๋ถ๋ง ์ฒดํฌ
Set<Integer> set = new HashSet<>();
for (int num : arr) set.add(num);
boolean isPresent = set.contains(4);
b. ๋ฌธ์์ด์ ๋น๋ ์นด์ดํธ
String s = "programming";
Map<Character, Integer> freq = new HashMap<>();
for (char c : s.toCharArray())
freq.put(c, freq.getOrDefault(c, 0) + 1);
๐ ์๋๊ทธ๋จ ๊ฒ์ฆ, ์ค๋ณต ํ์ง, ์ฌ๋ผ์ด๋ฉ ์๋์ฐ ๋ฑ์ ํ์ฉ
3. ํด์ฑ ์์ฉ ์์
a. ์ค๋ณต ํ์ง
Set<Integer> seen = new HashSet<>();
for (int num : arr) {
if (seen.contains(num)) { /* ์ค๋ณต ๋ฐ๊ฒฌ */ }
seen.add(num);
}
b. Two Sum ๋ฌธ์
Map<Integer, Integer> map = new HashMap<>();
for (int num : arr) {
if (map.containsKey(target - num)) {
// num๊ณผ target - num์ด ํ ์
}
map.put(num, 1);
}
c. ๋ถ๋ถํฉ = K ๋ฌธ์
- ๋์ ํฉ์ Key, ๋ฑ์ฅ ํ์๋ฅผ Value๋ก ํด์๋งต์ ์ ์ฅํด O(n) ํ์ด ๊ฐ๋ฅ
4. ํด์ ํจ์ ์ค๊ณ ํ
์ง์ ๊ตฌํ ์:
- ๋ฌธ์์ด: ๋คํญ ํด์ฑ(Polynomial Rolling Hash) ์์ฃผ ์ฌ์ฉ
hash = ฮฃ (s[i] * p^i) mod M - ํํ/๋ฐฐ์ด: ์์ ํด์๊ฐ ๊ฒฐํฉ
int hash(String s) {
int hash = 0, p = 31, M = 1_000_000_007;
for (int i = 0; i < s.length(); i++)
hash = (hash + s.charAt(i) * pow(p, i)) % M;
return hash;
}
โ ๏ธ ๋ณดํต Java/Python์ ๋ด์ฅ HashMap/HashSet์ ์ด๋ฏธ ์์ ํ ํด์ ํจ์๋ฅผ ์ฌ์ฉ
5. ์ฝ๋ฉ ํ ์คํธ์์ ํด์ฑ์ด ์์ฃผ ์ฐ์ด๋ ํจํด
| ํจํด | ํ์ฉ ์ฌ๋ก | ์์ |
|---|---|---|
| ๋น ๋ฅธ ์กด์ฌ ์ฌ๋ถ | ๊ฐ์ด ์กด์ฌํ๋์ง O(1)๋ก ํ์ธ | HashSet.contains(val) |
| ๋น๋ ์นด์ดํ | K-๋น๋, ์๋๊ทธ๋จ, ๋งค์นญ ๋ฌธ์ | map.getOrDefault(key, 0) |
| ์ฌ๋ผ์ด๋ฉ ์๋์ฐ | ๋ถ๋ถ ๋ฌธ์์ด ๊ณ ์ ์ฑ, ์๋๊ทธ๋จ ์ฐพ๊ธฐ | HashSet ๋๋ Rolling Hash |
| ๋ฉ๋ชจ์ด์ ์ด์ (DP) | ์ํ๋ณ ๊ฒฐ๊ณผ ์บ์ | Map<State, Result> |
| ๋ณตํฉ ํค | (a,b) ๋๋ ๋ฐฐ์ด์ Key๋ก ์ฌ์ฉ | Map<List, Value> / Map<Tuple, Value> |
| O(n) ์ต์ ํ ํธ๋ฆญ | ์ค์ฒฉ ๋ฃจํ ํผํ๊ธฐ | ๋ฐฉ๋ฌธ ์ฌ๋ถ ํด์๋ก ์ฒดํฌ |
6. ์ถฉ๋(Collision) ์ฒ๋ฆฌ ๋ฐฉ์
- ์ฒด์ด๋(Chaining): ๊ฐ์ ํด์์ฝ๋์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ฒฐ๋ฆฌ์คํธ๋ก ๊ด๋ฆฌ
- ์คํ ์ด๋๋ ์ฑ(Open Addressing): ์ถฉ๋ ์ ๋ค์ ์ธ๋ฑ์ค ํ์(์ ํ/์ด์ฐจ ํ์ฌ)
- ๋ก๋ ํฉํฐ(Load Factor): ์ผ์ ๋น์จ ์ด์ ์ฐจ๋ฉด ํด์ ํ ์ด๋ธ ํฌ๊ธฐ๋ฅผ ์ฌ์กฐ์ (Rehash)
Java, Python์ ํ์ค ํด์ ์๋ฃ๊ตฌ์กฐ๋ ์ด๋ฐ ๊ณผ์ ์ ์๋ ์ฒ๋ฆฌ
7. ์ค์/์ฃผ์์ฌํญ & ํ
- ํด์์ฝ๋๋ง ๋น๊ต๋ก ๋๋ฑ์ฑ ํ๋จ โ โ ๊ฐ ์์ฒด ๋น๊ต ํ์
- ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ฒด๋ Key๋ก ์ฌ์ฉํ์ง ๋ง ๊ฒ (์: List ๋์ Tuple/๋ถ๋ณ ๊ฐ์ฒด)
- ๋ณตํฉ ํค๋ ๊ตฌ๋ถ์๋ฅผ ๋ฃ๊ฑฐ๋ Tuple๋ก ์ ์ฅ
- Java์์๋
.equals()์.hashCode()ํจ๊ป ์ฌ์ ์
8. ๋ํ ํด์ ํ์ฉ ๋ฌธ์ (์ฝ๋ฉ ํ ์คํธ ๋น์ถ)
- ๋ฌธ์์ด์์ ์ฒซ ๋ฒ์งธ๋ก ์ค๋ณต๋์ง ์๋ ๋ฌธ์ ์ฐพ๊ธฐ
- ์๋๊ทธ๋จ ๊ทธ๋ฃนํ (์ ๋ ฌ๋ ๋ฌธ์์ด์ Key๋ก)
- ๋ถ๋ถํฉ์ด K์ธ ๋ถ๋ถ๋ฐฐ์ด ๊ฐ์
- ๊ฐ์ฅ ๊ธด ์ฐ์ ์์ด ์ฐพ๊ธฐ
- Two Sum
- ํ๋ณตํ ์(Happy Number) โ Set์ผ๋ก ๋ฌดํ ๋ฃจํ ๊ฐ์ง
9. ์ ๋ฆฌ ํ
| ๋ฌธ์ ์ ํ | ํด์ ํ์ฉ | ์์ฃผ ์ฐ๋ ์ฝ๋ ์์ |
|---|---|---|
| ์ค๋ณต ์ฒดํฌ | HashSet | if set.contains(val) ... |
| ๋น ๋ฅธ ์กฐํ/๋น๋ ๊ณ์ฐ | HashMap/Dictionary | map.getOrDefault(key, 0) |
| ์ฌ๋ผ์ด๋ฉ ์๋์ฐ | HashSet | set.add(substring) |
| ์๋๊ทธ๋จ/๊ทธ๋ฃนํ | Map<sorted String, List |
map.put(sort(s), list) |
| DP ๋ฉ๋ชจ์ด์ ์ด์ | Map<State, Result> | memo.put(state, result) |
๐ก Tip:
๋ํ ํด์ ํจํด(์ค๋ณต ์ฒดํฌ, ๋น๋์ ๊ณ์ฐ, Two Sum, ๋ถ๋ถํฉ, ์๋๊ทธ๋จ)์ ๋ฐ๋์ ์์ฝ๋ฉ์ผ๋ก ์ฐ์ตํ์ธ์.
Python dict/set, Java HashMap/HashSet API ์ฌ์ฉ๋ฒ๋ ์ต์ํด์ ธ์ผ ํฉ๋๋ค.
๐๏ธ ํด์ ํ ์ด๋ธ ์ถฉ๋ ์ฒ๋ฆฌ(Collision Handling) โ ์ฌ์ธต ๊ฐ์ด๋ & ์ฃผ์ ๊ธฐ๋ฒ
ํด์ ํ
์ด๋ธ์์๋ ์ถฉ๋(Collision) โ ์๋ก ๋ค๋ฅธ ํค๊ฐ ๋์ผํ ์ธ๋ฑ์ค์ ๋งคํ๋๋ ์ํฉ โ ์ด ํ์ฐ์ ์ผ๋ก ๋ฐ์ํฉ๋๋ค.
๊ฒฌ๊ณ ํ ์ถฉ๋ ์ฒ๋ฆฌ๋ ํ
์ด๋ธ์ด ๊ฐ๋ ์ฐจ๋๋ผ๋, ๋๋ ํด์ ํจ์๊ฐ ์๋ฒฝํ์ง ์๋๋ผ๋, ๋น ๋ฅธ ์ ์ฅ/์กฐํ/์ญ์ ์ฑ๋ฅ์ ์ ์งํ๋ ๋ฐ ํ์์
๋๋ค.
์๋๋ ์ฝ๋ฉ ํ
์คํธ ๊ด์ ์์ ์ถฉ๋ ์ฒ๋ฆฌ ๊ธฐ๋ฒ, ์๋ฆฌ, ์ฅ๋จ์ ์ ์์ธํ ์ ๋ฆฌํ ๋ด์ฉ์
๋๋ค.
1. ๋ถ๋ฆฌ ์ฒด์ด๋(Separate Chaining)
- ์๋ฆฌ: ํด์ ํ ์ด๋ธ์ ๊ฐ ์ฌ๋กฏ์ด ์ฐ๊ฒฐ ๋ฆฌ์คํธ(ํน์ ๊ท ํ ํธ๋ฆฌ)๋ฅผ ๊ฐ๋ฆฌํค๊ณ , ๊ฐ์ ํด์ ์ธ๋ฑ์ค์ ํด๋นํ๋ ๋ชจ๋ (Key, Value) ์์ ๊ทธ ๋ฆฌ์คํธ ์์ ์ ์ฅ
- ๋์ ๋ฐฉ์: ์ถฉ๋ ์ ํด๋น ์ธ๋ฑ์ค์ ๋ฆฌ์คํธ์ ์ ์์๋ฅผ ์ถ๊ฐ
- ์กฐํ: ์ธ๋ฑ์ค๋ก ์ ๊ทผํ ๋ค ๋ฆฌ์คํธ๋ฅผ ์ํํ๋ฉฐ ํค ํ์
- ์ญ์ : ๋ฆฌ์คํธ์์ ํด๋น ํค ์ ๊ฑฐ
- ์ฅ์ : ๊ตฌํ์ด ์ฝ๊ณ , ์ญ์ ํธ๋ฆฌ
- ๋จ์ : ์ธ๋ถ ํฌ์ธํฐ/๋ฆฌ์คํธ๋ก ์ธํ ์ถ๊ฐ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ, ์ฒด์ธ์ด ๊ธธ์ด์ง๋ฉด ์กฐํ ์๋ ๊ฐ์
์: ํ
์ด๋ธ ํฌ๊ธฐ๊ฐ N์ด๊ณ , ํด์๊ฐ key % size๋ผ๋ฉด, 7๊ณผ 14๋ ๋์ผํ ํด์ ์ฌ๋กฏ 0์ผ๋ก ์ด๋.
์ฌ๋กฏ 0์๋ ์ฐ๊ฒฐ ๋ฆฌ์คํธ [7 โ 14] ์ ์ฅ.
2. ์คํ ์ด๋๋ ์ฑ(Open Addressing)
๋ชจ๋ ํค๋ฅผ ํ ์ด๋ธ ๋ฐฐ์ด ์์ ์ง์ ์ ์ฅํ๋ฉฐ, ์ถฉ๋ ์ ์ผ์ ํ ๊ท์น(ํ๋ก๋น ์์)์ ๋ฐ๋ผ ๋ค์ ๋น ์ฌ๋กฏ์ ํ์ํด ์ฝ์ .
์ข ๋ฅ:
a. ์ ํ ํ์ฌ(Linear Probing)
- ํ์ฌ ์์: ์ฌ๋กฏ
h๊ฐ ์ฐจ ์์ผ๋ฉด(h+1) % size,(h+2) % size, โฆ ์์๋๋ก ํ์ - ์ฅ์ : ๊ตฌํ๊ณผ ๊ฐ๋ ๊ฐ๋จ, ์บ์ ์นํ์
- ๋จ์ : 1์ฐจ ๊ตฐ์งํ(Primary Clustering) ๋ฌธ์ ๋ก ํค๋ค์ด ๋ชฐ๋ ค ์๋๊ฐ ๋๋ ค์ง ์ ์์
b. ์ด์ฐจ ํ์ฌ(Quadratic Probing)
- ํ์ฌ ์์:
(h+1ยฒ),(h+2ยฒ)โฆ (mod size) - ์ฅ์ : ์ ํ ํ์ฌ์ ๋นํด ๊ตฐ์งํ ๊ฐ์
- ๋จ์ : 2์ฐจ ๊ตฐ์งํ(Secondary Clustering) ๊ฐ๋ฅ์ฑ, ํ ์ด๋ธ ํฌ๊ธฐ ์กฐ๊ฑด(์์ ๋ฑ) ๋ฐ๋ผ ๋ชจ๋ ์ฌ๋กฏ ํ์ ๋ชป ํ ์ ์์
c. ์ด์ค ํด์ฑ(Double Hashing)
- ํ์ฌ ์์: ๋ ๋ฒ์งธ ํด์ ํจ์๋ฅผ ์ฌ์ฉํด ๋ณดํญ(step) ๊ฒฐ์
next = (h + i * hash2(key)) % size - ์ฅ์ : ๊ตฐ์งํ ์ต์ํ, ๊ท ๋ฑ ๋ถํฌ
- ๋จ์ : ๋ณด์กฐ ํด์ ํจ์ ์ค๊ณ ํ์, ๊ตฌํ ๋ณต์ก
์คํ ์ด๋๋ ์ฑ ํน์ง:
- ํค๋ฅผ ํ ์ด๋ธ ์์๋ง ์ ์ฅ
- ์กฐํ/์ฝ์ ์ ๋์ผํ ํ๋ก๋น ์์ ์ฌ์ฉ
- ์ญ์ ์ ์ฃผ์ ํ์: ์ญ์ ๋ง์ปค ์ฌ์ฉ or ๋ค ์์ ์ฌ๋ฐฐ์น ํ์
- **๋ก๋ ํฉํฐ(load factor)**๊ฐ ๋ฎ์ ๋(โค0.75) ์ฑ๋ฅ์ด ์ข์
3. ๊ธฐํ ์ถฉ๋ ์ฒ๋ฆฌ ๊ธฐ๋ฒ
๋ก๋น ํ๋ ํด์ฑ(Robin Hood Hashing)
- ์ถฉ๋ ์, ํ์ฌ ํค์ ์ ํค์ โ์ด์์ ์ธ ์ฌ๋กฏ์ผ๋ก๋ถํฐ ๊ฑฐ๋ฆฌ(probe distance)โ๋ฅผ ๋น๊ตํ์ฌ, ๋ ๋จผ ํค๋ฅผ ๋ค๋ก ๋ฐ๊ณ ๊ทผ์ ํ ํค๋ฅผ ์์ผ๋ก ๋ฐฐ์นํด ์ ์ฒด ํ๊ท ํ์ฌ ๊ฑฐ๋ฆฌ๋ฅผ ๊ท ๋ฑํ๊ฒ ์ ์ง
- ์ฅ์ : ์ฑ๋ฅ ์์ธก ์ฉ์ด
- ๋จ์ : ์ฝ์ ๊ณผ์ ๋ณต์ก
์ฟ ์ฟ ํด์ฑ(Cuckoo Hashing)
- ๊ฐ ํค๊ฐ ๊ฐ๋ฅํ ์ฌ๋กฏ ๋ ๊ฐ(๋ ๊ฐ์ ํด์ ํจ์๋ก ๊ฒฐ์ )๋ฅผ ๊ฐ์ง
- ๋ ์ฌ๋กฏ ๋ค ์ฐจ ์์ผ๋ฉด ๊ธฐ์กด ํค๋ฅผ โ์ซ์๋ด๊ณ (kick)โ ๋ค๋ฅธ ์ฌ๋กฏ์ผ๋ก ์ฌ๋ฐฐ์น, ํ์์ ๋ฐ๋ณต
- ์ฅ์ : O(1) ์กฐํ ๋ณด์ฅ
- ๋จ์ : ์ฝ์ ์ด ๋ณต์กํ๊ณ , ํ ์ด๋ธ ์ฌํด์ฑ ํ์ํ ์ ์์
ํ์ค์ฝง์น ํด์ฑ(Hopscotch Hashing)
- ์ ํ ํ์ฌ์ ์ ์ฌํ๋, ๊ฐ ์ฌ๋กฏ ์ฃผ๋ณ์ โ์ด์ ์งํฉ(neighborhood)โ ๋ด์์ ํค ์ฌ๋ฐฐ์น ๊ฐ๋ฅ
โ ์บ์ ํจ์จ๊ณผ ํ์ฌ ์ฑ๋ฅ ํฅ์
4. ๋น๊ต ํ & ํ
| ๋ฐฉ๋ฒ | ์กฐํ ์๋ | ๋ฉ๋ชจ๋ฆฌ ์ค๋ฒํค๋ | ์ญ์ ํธ์ | ๊ตฐ์งํ ์ํ |
|---|---|---|---|---|
| ๋ถ๋ฆฌ ์ฒด์ด๋ | ์ข์ | ๋์(๋ฆฌ์คํธ) | ์ฌ์ | ๋ฎ์ |
| ์ ํ ํ์ฌ | ๋งค์ฐ ์ข์ | ๋ฎ์ | ์ด๋ ค์ | ๋์(1์ฐจ ๊ตฐ์งํ) |
| ์ด์ฐจ ํ์ฌ | ์ข์ | ๋ฎ์ | ์ด๋ ค์ | ๋ณดํต(2์ฐจ ๊ตฐ์งํ) |
| ์ด์ค ํด์ฑ | ๋งค์ฐ ์ข์ | ๋ฎ์ | ์ด๋ ค์ | ๋ฎ์ |
| ์ฟ ์ฟ /ํ์ค์ฝง์น | ๋งค์ฐ ์ข์ | ๋ณดํต | ๋ณต์กํจ | ๋งค์ฐ ๋ฎ์ |
- ์ฒด์ด๋: ๋์ ๋ก๋ ํฉํฐ ํ์ฉ ๊ฐ๋ฅ, ์ญ์ ๋ง์ ๊ฒฝ์ฐ ์ ๋ฆฌ
- ์คํ ์ด๋๋ ์ฑ: ๋ฉ๋ชจ๋ฆฌ ํจ์จ ๋์, ํ์ง๋ง ๋ก๋ ํฉํฐ ์์น ์ ์ฑ๋ฅ ์ ํ โ ์กฐ๊ธฐ ๋ฆฌ์ฌ์ด์ง ํ์
- ์ข์ ํด์ ํจ์์ ์ ์ ํ ํ ์ด๋ธ ํฌ๊ธฐ ์กฐ์ ์ด ์ถฉ๋ ์ต์ํ์ ํต์ฌ
- ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ฒด๋ ํด์ ํค๋ก ์ฌ์ฉ ์ง์, ํญ์ ๊ฐ ์์ฒด ๋น๊ต๋ก ๋๋ฑ์ฑ ํ๋จ
5. Java/Python์์์ ์ถฉ๋ ์ฒ๋ฆฌ
- Java
HashMap: ๋ถ๋ฆฌ ์ฒด์ด๋ ๊ธฐ๋ฐ (Java 8๋ถํฐ ์ฒด์ธ ๊ธธ์ด ์ปค์ง๋ฉด ํธ๋ฆฌ๋ก ๋ณํ) - Python
dict/set: 3.3 ๋ฒ์ ๋ถํฐ ๊ฐ์ ๋ ์คํ ์ด๋๋ ์ฑ ๋ฐฉ์ ์ฌ์ฉ
โ
์ฝ๋ฉ ํ
์คํธ ํ:
์ง์ ํด์ ํ
์ด๋ธ ๊ตฌํ ๋ฌธ์ ๊ฐ ๋์ค๋ฉด, ๋ถ๋ฆฌ ์ฒด์ด๋๊ณผ ์คํ ์ด๋๋ ์ฑ(์ ํ ํ์ฌ) ๋ ๊ฐ์ง๋ ์์ฝ๋ฉ ๊ฐ๋ฅํด์ผ ํฉ๋๋ค.
references