分治算法 (Divide and Conquer)

🧮 分治算法 (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

分治算法遵循三个核心步骤:

  1. 分解 (Divide):将原问题划分为若干个规模较小、相互独立、与原问题形式相同的子问题
  2. 治理 (Conquer):递归地解决子问题;如果子问题足够小,则直接求解
  3. 合并 (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

  1. LeetCode 53 - 最大子序和 - 简单
  2. LeetCode 169 - 多数元素 - 简单
  3. LeetCode 50 - Pow(x, n) - 中等
  4. LeetCode 4 - 寻找两个有序数组的中位数 - 困难

*本文由 AI 自动生成 Generated by AI*