12-1 공간으로 시간을 살 수 있나요?
12-2 해싱
12-3 백트래킹
| 방법 | 시간 복잡도 | 공간 복잡도 |
|---|---|---|
| 재귀 (분할정복) | O(2ⁿ) | O(1) |
| 행렬 거듭제곱 | O(log n) | O(1) |
| 동적 계획법 (DP) | O(n) | O(n) |
| 테이블 미리 계산 후 사용 | O(1) | O(n) |


아파트 단지에서 공용 우편함을 사용한다면 편지 찾기 어렵죠?
하지만 세대별 우편함이 있다면 금방 찾을 수 있어요.
→ 해싱은 바로 이런 개념!
데이터를 저장할 위치를 미리 계산해 바로 접근합니다.
| 탐색법 | 특징 | 조건 |
|---|---|---|
| 순차 탐색 | 처음부터 하나씩 비교 | 정렬 불필요 |
| 이진 탐색 | 중간값 기준으로 절반씩 탐색 | 정렬 필수 |
| 해싱 (Hashing) | 위치를 계산해 바로 접근 | 해시 함수 필요 |


# 숫자형 키에 대한 가장 기본적인 해시 함수
def hashFn(key):
return key % M # M은 테이블 크기
h("뉴욕") = 3
h("뮌헨") = 3 → 충돌 발생

나머지 연산자 mod(또는 % 연산자)
해시 테이블의 크기 M을 1과 자기 자신만을 약수로 가지는 소수(prime number)로 선택하는 것이 좋음
해싱에서 가장 흔히 사용되지만 항상 성능이 좋지는 않음
보완하기 위한 방법:
a부터 z를 1부터 26에 대응시킬 수 있음def hashFnStr(key)
sum = 0
for c in key: # 문자열의 모든 문자에 대해
sum = sum + (ord(c)) # 그 문자의 아스키 코드값을 sum에 더함
return sum % M
# 충돌 발생 시 한 칸씩 이동하며 빈자리 찾음
while table[id] is not None:
id = (id + 1) % M
조사
ht[k]에서 충돌이 발생했다면 다음 위치인 ht[k+1]부터 순서대로 비어 있는지를 살피고, 빈 곳이 있으면 저장함삽입 연산
+1씩 이동M = 13 # 해시 테이블 크기
table = [None] * M
def hashFn(key):
return key % M
def lp_insert(key):
id = hashFn(key)
count = M
while count > 0 and table[id] not in (None, -1): # 빈 버킷 또는 삭제된 자리(-1) 찾기
id = (id + 1) % M
count -= 1
if count > 0:
table[id] = key
45 → 27 → 88 → 9 → 71 → 60 → 46 → 38 → 24


24는 끝까지 가도 비어 있는 자리가 없어서 테이블 맨 앞으로 되돌아와 저장됨
탐색 연산
+1씩 이동
def lp_search(key):
id = hashFn(key)
count = M
while count > 0:
if table[id] == None:
return None # 테이블에 없음
if table[id] == key:
return table[id] # 키 발견
id = (id + 1) % M
count -= 1
return None
lp_search(46) → 충돌을 피해 선형 조사 후 위치 찾기 성공lp_search(39) → 중간에 빈 슬롯(None)을 만나 탐색 실패삭제 연산
None으로 지우면 이후 탐색이 끊겨 탐색 실패 가능성 발생60을 먼저 삭제하면, 46 탐색 시 중간에 멈춰버림-1은 "지워졌지만 지나가야 하는 자리"로 인식됨
def lp_delete(key):
id = hashFn(key)
count = M
while count > 0:
if table[id] == None:
return # 없음
if table[id] != -1 and table[id] == key:
table[id] = -1 # 삭제 마킹
return
id = (id + 1) % M
count -= 1
-1을 빈 슬롯처럼 인식하도록 변경 필요:while count > 0 and table[id] not in (None, -1):
+1, +4, +9, ... 식으로 증가. 군집화 완화 가능 || 전략 | 설명 | 연산량 |
|---|---|---|
| 브루트포스 | N² 칸 중 N개를 무작위 선택 후 유효성 검사 | C(N², N) (조합) |
| 백트래킹 | 한 행씩 퀸을 두며 유망하지 않으면 되돌아감 | 훨씬 적은 탐색 |
def isSafe(board, x, y):
N = len(board)
# 세로 방향
for i in range(y):
if board[i][x] == 1:
return False
# 왼쪽 대각선 ↖
for i, j in zip(range(y-1, -1, -1), range(x-1, -1, -1)):
if board[i][j] == 1:
return False
# 오른쪽 대각선 ↗
for i, j in zip(range(y-1, -1, -1), range(x+1, N)):
if board[i][j] == 1:
return False
return True
def solve_N_Queen(board, y):
N = len(board)
if y == N: # 모든 행에 퀸을 놓았다면 출력
printBoard(board)
print()
return
for x in range(N):
if isSafe(board, x, y):
board[y][x] = 1
solve_N_Queen(board, y + 1)
board[y][x] = 0 # 백트래킹
def solve_N_Queen(board, y):
N = len(board)
if y == N: # 모든 행에 퀸을 놓았다면 출력
printBoard(board)
print()
return
for x in range(N):
if isSafe(board, x, y):
board[y][x] = 1
solve_N_Queen(board, y + 1)
board[y][x] = 0 # 백트래킹
. Q . .
. . . Q
Q . . .
. . Q .
. . Q .
Q . . .
. . . Q
. Q . .