🧮 分治算法 (Divide and Conquer)
难度 / Difficulty: 中等 (Medium)
分类 / Category: 算法设计范式 (Algorithm Design Paradigm)
时间复杂度 / Time Complexity: O(n log n) 或 O(n)
空间复杂度 / Space Complexity: O(n) 或 O(log n)
📖 算法简介 / Introduction
分治算法是一种将复杂问题分解为若干个相似的子问题,递归求解子问题,再合并结果得到原问题解的算法思想。分治的核心在于”分而治之”,把大问题拆成小问题分别解决。
Divide and Conquer is an algorithmic paradigm that breaks a problem into smaller subproblems of the same type, recursively solves them, and then combines their results to solve the original problem.
💡 算法原理 / Principle
分治算法遵循三个核心步骤:
- 分解 (Divide):将原问题划分为若干个规模较小、相互独立、与原问题形式相同的子问题
- 治理 (Conquer):递归地解决子问题;如果子问题足够小,则直接求解
- 合并 (Combine):将子问题的解合并为原问题的解
核心思想:Recursively break down a problem into two or more sub-problems of the same or related type, until these become simple enough to be solved directly. The solutions to the sub-problems are then combined to give a solution to the original problem.
🔑 关键概念 / Key Concepts
| 概念 | 说明 |
|---|---|
| 递归出口 (Base Case) | 最小子问题的解,无需继续分解 |
| 子问题独立性 | 子问题之间无依赖,可并行求解 |
| 合并策略 (Combine) | 如何将子解合并为原解,是算法效率的关键 |
| 递归深度 | 影响空间复杂度和栈溢出风险 |
| -master 定理 | 估算分治算法时间复杂度的工具 |
📝 代码实现 / Implementation
# 归并排序 - 分治经典应用
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
# 示例
arr = [38, 27, 43, 3, 9, 82, 10]
print(merge_sort(arr))
# 输出: [3, 9, 10, 27, 38, 43, 82]
# 快速排序
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
# 示例
arr = [3, 6, 8, 10, 1, 2, 1]
print(quick_sort(arr))
# 输出: [1, 1, 2, 3, 6, 8, 10]
# 最近点对问题
def closest_pair(points):
if len(points) <= 3:
return brute_force_closest(points)
mid = len(points) // 2
mid_x = points[mid][0]
left = points[:mid]
right = points[mid:]
dl = closest_pair(left)
dr = closest_pair(right)
d = min(dl, dr)
strip = [p for p in points if abs(p[0] - mid_x) < d]
return min(d, strip_closest(strip, d))
✨ 示例 / Example
归并排序流程:
- 输入:
[38, 27, 43, 3, 9, 82, 10] - 分解:
[38, 27, 43, 3]和[9, 82, 10] - 递归排序:
[3, 27, 38, 43]和[9, 10, 82] - 合并:
[3, 9, 10, 27, 38, 43, 82]
🎯 应用场景 / Applications
- 排序算法 — 归并排序、快速排序
- 最近点对 — 二维/三维空间中找最近的两个点
- 大整数乘法 — Karatsuba 算法
- 矩阵乘法 — Strassen 算法
- 二分搜索 — 有序数组查找
- 傅里叶变换 — FFT 快速频域转换
- 汉诺塔 — 经典递归问题
📊 复杂度分析 / Complexity Analysis
| 算法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 归并排序 | O(n log n) | O(n) |
| 快速排序 | O(n log n)(平均) | O(log n) |
| 最近点对 | O(n log n) | O(n) |
| Karatsuba 乘法 | O(n^log₂³) ≈ O(n^1.585) | O(n) |
🏠 实战例题 / Practice Problems
- LeetCode 53 - 最大子序和 - 简单
- LeetCode 169 - 多数元素 - 简单
- LeetCode 50 - Pow(x, n) - 中等
- LeetCode 4 - 寻找两个有序数组的中位数 - 困难
| *本文由 AI 自动生成 | Generated by AI* |