분할 정복(Divide and Conquer) 알고리즘은 문제를 더 작은 하위 문제로 나누어 해결하는 기법입니다. 이 방법은 재귀적 성질을 가지고 있으며, 주로 시간 복잡도를 줄이고 큰 문제를 효율적으로 해결할 수 있습니다.
특히 거듭제곱 계산, 최대 구간 합 문제, 행렬 곱셈 최적화와 같은 문제들에서 주로 사용됩니다.
분할 정복은 문제를 작은 단위로 나누어 문제를 해결하기 때문에, 많은 경우 시간 복잡도를 획기적으로 줄일 수 있습니다. 예를 들어, 배열의 원소를 분할하여 정렬하는 병합 정렬(Merge Sort)의 시간 복잡도는 $$O(n \log n)$$입니다.
분할 정복의 일반적인 시간 복잡도는 다음과 같은 재귀 관계식으로 표현됩니다:
$$T(n) = a \cdot T\left(\frac{n}{b}\right) + f(n)$$
여기서:
이 관계식을 사용해 분할 정복 알고리즘의 시간 복잡도를 분석할 수 있습니다.
분할 정복을 활용한 거듭제곱 계산은 큰 수의 거듭제곱을 효율적으로 구하는 대표적인 예제입니다. 일반적인 거듭제곱 계산은 시간 복잡도가 $$O(n)$$이지만, 분할 정복을 사용하면 이를 $$O(\log n)$$으로 줄일 수 있습니다.
풀이 접근:
Python 코드 예제:
def power(x, n):
if n == 0:
return 1
elif n % 2 == 0:
half = power(x, n // 2)
return half * half
else:
half = power(x, (n - 1) // 2)
return half * half * x
# 예제 사용
print(power(2, 10)) # 출력: 1024
설명: 이 함수는 분할 정복을 통해 지수를 절반으로 줄이며, 각 단계에서 곱셈을 통해 결과를 계산합니다. 시간 복잡도는 $$O(\log n)$$이 되어 큰 수의 거듭제곱을 매우 효율적으로 계산할 수 있습니다.
최대 구간 합 문제는 배열에서 연속된 부분 배열의 합이 최대가 되는 값을 찾는 문제로, 분할 정복을 통해 시간 복잡도를 $$O(n \log n)$$으로 줄일 수 있습니다.
풀이 접근:
Python 코드 예제:
def max_crossing_sum(arr, left, mid, right):
# 왼쪽 구간 최대 합 계산
left_sum = float('-inf')
sum = 0
for i in range(mid, left - 1, -1):
sum += arr[i]
if sum > left_sum:
left_sum = sum
# 오른쪽 구간 최대 합 계산
right_sum = float('-inf')
sum = 0
for i in range(mid + 1, right + 1):
sum += arr[i]
if sum > right_sum:
right_sum = sum
return left_sum + right_sum
def max_subarray_sum(arr, left, right):
if left == right:
return arr[left]
mid = (left + right) // 2
return max(max_subarray_sum(arr, left, mid), # 왼쪽 구간 최대 합
max_subarray_sum(arr, mid + 1, right), # 오른쪽 구간 최대 합
max_crossing_sum(arr, left, mid, right)) # 중간을 가로지르는 최대 합
# 예제 사용
arr = [2, -4, 3, -1, 2, -4, 5, -3]
print(max_subarray_sum(arr, 0, len(arr) - 1)) # 출력: 최대 구간 합
설명: 이 알고리즘은 배열을 절반으로 나눈 후, 각 구간에 대해 최대 구간 합을 계산하여 병합합니다. 중간을 가로지르는 구간을 포함하는 최대 합을 계산하기 위해 max_crossing_sum
함수를 사용하며, 이를 통해 효율적으로 최대 구간 합을 찾습니다.
이번 글에서는 분할 정복의 심화 개념과 고급 문제인 최대 구간 합 문제와 거듭제곱 계산을 학습했습니다. 분할 정복은 문제를 체계적으로 해결하는 강력한 기법으로, 다양한 문제에 적용하여 효율적인 풀이를 연습해 보세요!