《JavaScript算法》递归&分治

52 阅读2分钟

递归是一种算法设计技巧,其中函数通过调用自身来解决问题。分治策略是递归的一个子集,它将问题分解为几个较小的子问题,独立地解决这些子问题,然后合并它们的答案来解决原问题。

基础递归模板

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;
}

常见题型

  1. 二叉树遍历:前序、中序、后序遍历通常使用递归。
  2. 反转链表:可以使用递归来实现。
  3. 求斐波那契数:经典的递归示例,但也可以使用迭代或动态规划来优化。
  4. 合并排序:分治的经典示例,将数组分成两半,独立排序,然后合并。
  5. 快速排序:选择一个基准元素,将数组分为两部分,一部分的元素小于基准,另一部分的元素大于基准,然后递归排序这两部分。
  6. 求二叉树的最大深度:使用递归来比较左右子树的深度。
  7. Pow(x, n) :计算x的n次方可以使用分治,将其分解为更小的部分。
  8. 大数乘法:如Karatsuba算法。
  9. Strassen矩阵乘法:使用分治策略加速矩阵乘法。
  10. 最接近的点对问题:在二维平面上,找到最近的两个点。

递归和分治是非常强大的算法设计技巧,可以帮助解决许多看似复杂的问题。但它们也有其限制,如可能导致栈溢出(对于递归深度过大的情况)。在实际应用中,很重要的一点是理解何时使用它们,以及如何正确、高效地实现。