출시·고도화 중
Algorithm
분할 정복은 문제를 작은 부분 문제로 나누어 재귀적으로 풀고 답을 합치는 설계 기법으로, 병합 정렬·빠른 거듭제곱·퀵셀렉트의 바탕입니다.
분할 정복(divide and conquer)은 문제를 같은 모양의 더 작은 부분 문제로 나누고(분할), 각 부분 문제를 재귀적으로 푼 뒤(정복), 그 답을 모아 원래 문제의 답을 만드는(합치기) 알고리즘 설계 기법입니다. 병합 정렬, 이진 탐색, 빠른 거듭제곱, 퀵셀렉트, 카라추바 곱셈, 최근접 점 쌍 알고리즘이 모두 이 틀을 따릅니다.
분할 정복이 중요한 이유는 모든 경우를 확인하는 O(n^2) 풀이를 O(n log n)이나 O(log n)으로 줄이는 경우가 많기 때문입니다. 역순 쌍 세기처럼 경계를 넘는 정보를 합치기 단계에서 효율적으로 계산하는 발상은 코딩 테스트에 자주 나오고, 정렬 라이브러리, 큰 수 곱셈, FFT, 암호의 모듈러 거듭제곱 같은 실제 시스템에서도 쓰입니다.
공부할 때는 먼저 병합 정렬을 손으로 추적하며 분할, 정복, 합치기의 흐름을 익히고, T(n) = aT(n/b) + f(n) 같은 점화식을 세워 마스터 정리로 실행 시간을 구하는 연습을 합니다. 이어서 역순 쌍 세기, 빠른 거듭제곱, 퀵셀렉트를 직접 구현해 보고, 부분 문제가 겹칠 때는 동적 계획법이 필요하다는 차이까지 구분할 수 있으면 됩니다.
문제를 나누고, 부분 문제를 재귀로 풀고, 답을 합칩니다. 기저 사례가 재귀를 멈추고, 대개 합치기 비용이 전체 성능을 좌우합니다.
실행 시간을 T(n) = aT(n/b) + f(n)으로 나타내고 f(n)을 n^(log_b a)와 비교하면 병합 정렬의 O(n log n) 같은 결과를 바로 얻습니다.
역순 쌍 세기나 최대 부분 배열처럼 양쪽 절반에 걸친 경우를 합치기 단계에서 선형 시간에 처리하는 것이 핵심 발상입니다.
이진 탐색, 빠른 거듭제곱, 퀵셀렉트처럼 부분 문제를 하나만 남기면 O(log n)이나 기댓값 O(n) 알고리즘이 됩니다.
sort_count는 병합 정렬로 리스트를 정렬하면서, 오른쪽 절반의 원소가 먼저 병합될 때마다 왼쪽에 남은 원소 수를 더해 역순 쌍을 O(n log n)에 셉니다. power는 지수를 절반으로 줄여 가며 제곱하는 빠른 거듭제곱으로, 곱셈을 O(log e)번만 합니다. python divide_and_conquer.py로 실행하면 정렬 결과와 역순 쌍 14개, 3^200을 1,000,000,007로 나눈 나머지가 출력됩니다.
divide_and_conquer.py
def sort_count(a):
"""Return (sorted list, number of inversions) using merge sort."""
if len(a) <= 1:
return list(a), 0
mid = len(a) // 2
left, x = sort_count(a[:mid])
right, y = sort_count(a[mid:])
merged, i, j, cross = [], 0, 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
merged.append(left[i])
i += 1
else:
merged.append(right[j])
j += 1
cross += len(left) - i # right[j] is smaller than every left[i:]
merged += left[i:] + right[j:]
return merged, x + y + cross
def power(base, exp, mod):
"""base ** exp % mod with O(log exp) multiplications."""
if exp == 0:
return 1 % mod
half = power(base, exp // 2, mod)
result = half * half % mod
return result * base % mod if exp % 2 else result
if __name__ == "__main__":
print(sort_count([5, 2, 4, 7, 1, 3, 2, 6])) # ([1, 2, 2, 3, 4, 5, 6, 7], 14)
print(power(3, 200, 1_000_000_007)) # 136318165
python divide_and_conquer.py설치부터 분할 정복 의 핵심 개념까지, 여섯 장으로 차근차근 따라 합니다.
분할 정복 에 관해 묻고, 경험을 나누고, 의견을 주고받는 곳입니다.
아직 토론이 없습니다. 첫 이야기를 시작해 보세요.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.