递归是一种算法设计技巧,其中函数通过调用自身来解决问题。分治策略是递归的一个子集,它将问题分解为几个较小的子问题,独立地解决这些子问题,然后合并它们的答案来解决原问题。
基础递归模板
function recursiveFunction(params) {
// 基本情况(终止条件)
if (baseCase) {
return someValue;
}
// 递归调用
return recursiveFunction(updatedParams);
}
基础分治模板
function divideAndConquer(problem, params) {
// 基本情况
if (baseCase) {
return someValue;
}
// 将问题分解为子问题
subproblems = splitProblem(problem);
// 解决子问题
subResult1 = divideAndConquer(subproblems[0], updatedParams);
subResult2 = divideAndConquer(subproblems[1], updatedParams);
// ...
// 合并或组合子问题的解决方案以获得原问题的解决方案
result = mergeOrCombine(subResult1, subResult2, ...);
return result;
}
常见题型
- 二叉树遍历:前序、中序、后序遍历通常使用递归。
- 反转链表:可以使用递归来实现。
- 求斐波那契数:经典的递归示例,但也可以使用迭代或动态规划来优化。
- 合并排序:分治的经典示例,将数组分成两半,独立排序,然后合并。
- 快速排序:选择一个基准元素,将数组分为两部分,一部分的元素小于基准,另一部分的元素大于基准,然后递归排序这两部分。
- 求二叉树的最大深度:使用递归来比较左右子树的深度。
- Pow(x, n) :计算x的n次方可以使用分治,将其分解为更小的部分。
- 大数乘法:如Karatsuba算法。
- Strassen矩阵乘法:使用分治策略加速矩阵乘法。
- 最接近的点对问题:在二维平面上,找到最近的两个点。
递归和分治是非常强大的算法设计技巧,可以帮助解决许多看似复杂的问题。但它们也有其限制,如可能导致栈溢出(对于递归深度过大的情况)。在实际应用中,很重要的一点是理解何时使用它们,以及如何正确、高效地实现。