分治法是一种问题解决方法,它将一个复杂的问题分解成若干个规模更小的、相似的子问题,然后递归地求解这些子问题,最后将子问题的解合并起来,以解决原问题。本页将探讨分治算法模式、其特点以及其应用的经典示例。
关于回溯法(一种可能看起来相似的递归问题解决方法),请参阅回溯算法。关于动态规划(用于处理重叠子问题),请参阅动态规划。
分治法包含三个基本步骤:
为了应用分治法,问题应满足以下特点:
资料来源:docs/chapter_divide_and_conquer/binary_search_recur.md9-20 docs/chapter_divide_and_conquer/build_binary_tree_problem.md9-16
分治法与其他算法方法有相似之处,但也有关键区别:
| 算法范式 | 子问题处理 | 最优性 | 典型复杂度 |
|---|---|---|---|
| 分治法 | 独立的子问题 | 找到精确解 | 通常为 O(n log n) |
| 动态规划 | 带有记忆化的重叠子问题 | 找到最优解 | 通常为 O(n²) |
| 回溯 | 通过剪枝探索解空间 | 找到所有有效的解 | 通常为 O(2ⁿ) |
虽然这三种方法都涉及分解问题,但分治法侧重于独立的子问题,而动态规划处理重叠子问题。回溯法则使用试错法探索整个解空间。
资料来源:docs/chapter_dynamic_programming/intro_to_dynamic_programming.md4-6 docs/chapter_backtracking/backtracking_algorithm.md3-5 docs/chapter_dynamic_programming/dp_problem_features.md3-7
二分查找使用分治法在一个已排序的数组中高效地查找目标元素。
使用分治法实现二分查找
资料来源:docs/chapter_divide_and_conquer/binary_search_recur.md21-45
给定二叉树的前序遍历和中序遍历,我们可以使用分治法来重建该树。
分解:
解决:使用各自的遍历部分递归地构建左子树和右子树。
合并:将子树连接到根节点,形成完整的树。
从遍历构建二叉树的实现
资料来源:docs/chapter_divide_and_conquer/build_binary_tree_problem.md16-38 docs/chapter_divide_and_conquer/build_binary_tree_problem.md52-64
汉诺塔问题清晰地展示了分治法的原理。
分解:将移动 n 个盘子的问题分解为:
解决:递归地解决移动 n-1 个盘子的子问题。
合并:按顺序执行这些步骤即可解决整个问题。
解决汉诺塔问题的实现
资料来源:docs/chapter_divide_and_conquer/hanota_problem.md19-91
分治算法的时间复杂度通常遵循以下递推关系:
$$T(n) = a \cdot T(n/b) + O(n^d)$$
其中
这将导致以下时间复杂度:
示例复杂度分析
资料来源:docs/chapter_divide_and_conquer/binary_search_recur.md39-45 docs/chapter_divide_and_conquer/build_binary_tree_problem.md97-99 docs/chapter_divide_and_conquer/hanota_problem.md89-91
分治算法通常遵循这种递归实现模式:
function divideAndConquer(problem):
// Base case
if problem is small enough:
return solve(problem) directly
// Divide step
divide problem into subproblems
// Conquer step
for each subproblem:
solve recursively
// Combine step
return combined results
成功实现分治法的关键方面包括:
资料来源:docs/chapter_divide_and_conquer/binary_search_recur.md39-45 docs/chapter_divide_and_conquer/build_binary_tree_problem.md57-63 docs/chapter_divide_and_conquer/hanota_problem.md83-88
分治算法是一种强大的算法范式,它通过将问题分解为更小、可管理的子问题来解决问题。当满足以下条件时,它特别有效:
这种方法催生了许多高效的算法,包括二分查找、归并排序、快速排序,以及解决汉诺塔等复杂问题的算法。理解何时以及如何应用分治法对于算法设计和优化至关重要。