diff --git a/docs/chapter_dynamic_programming/dp_problem_features.md b/docs/chapter_dynamic_programming/dp_problem_features.md index b131a8c14..ed32c6e2f 100644 --- a/docs/chapter_dynamic_programming/dp_problem_features.md +++ b/docs/chapter_dynamic_programming/dp_problem_features.md @@ -24,7 +24,7 @@ $$ 这便可以引出「最优子结构」的含义:**原问题的最优解是从子问题的最优解构建得来的**。对于本题,我们从两个子问题最优解 $dp[i-1]$ , $dp[i-2]$ 中挑选出较优的那一个,并用它构建出原问题 $dp[i]$ 的最优解。 -相较于分治算法问题,动态规划问题的解也是由其子问题的解构成的。不同的是,**动态规划中子问题的解不仅揭示了问题的局部最优解,而且还通过特定的递推关系链接起来,共同构建出原问题的全局最优解**。 +相较于分治问题,动态规划问题的解也是由其子问题的解构成的。不同的是,**动态规划中子问题的解不仅揭示了问题的局部最优解,而且还通过特定的递推关系链接起来,共同构建出原问题的全局最优解**。 那么,上节的爬楼梯题目有没有最优子结构呢?它要求解的是方案数量,看似是一个计数问题,但如果换一种问法:求解最大方案数量。我们意外地发现,**虽然题目修改前后是等价的,但最优子结构浮现出来了**:第 $n$ 阶最大方案数量等于第 $n-1$ 阶和第 $n-2$ 阶最大方案数量之和。所以说,最优子结构的是一个比较宽泛的概念,在不同问题中会有不同的含义。 diff --git a/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md b/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md index 87d57c628..eb32cf2d1 100644 --- a/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md +++ b/docs/chapter_dynamic_programming/intro_to_dynamic_programming.md @@ -2,7 +2,7 @@ 「动态规划 Dynamic Programming」是一种用于解决复杂问题的优化算法,它把一个问题分解为一系列更小的子问题,并把子问题的解存储起来以供后续使用,从而避免了重复计算,提升了解题效率。 -在本节中,我们先从一个动态规划经典例题入手,了解动态规划是如何高效地求解问题的。 +在本节中,我们先从一个动态规划的经典例题入手,先给出它的暴力回溯解法,观察其中包含的重叠子问题,再一步步导出更高效的动态规划解法。 !!! question "爬楼梯" @@ -471,4 +471,8 @@ $$ **我们将这种空间优化技巧称为「状态压缩」**。在许多动态规划问题中,当前状态仅与前面有限个状态有关,不必保存所有的历史状态,这时我们可以应用状态压缩,只保留必要的状态,通过“降维”来节省内存空间。 -实际上,所有动态规划问题都可以使用回溯算法解决,因为回溯算法本质上就是穷举,它能够遍历决策树的所有可能的状态,并从中记录需要的解。 \ No newline at end of file +总的看来,子问题分解是一种通用的算法思路,在分治算法、动态规划、回溯算法中各有特点: + +- 分治算法将原问题划分为几个独立的子问题,然后递归解决子问题,最后合并子问题的解得到原问题的解。例如,归并排序将长数组不断划分为两个短子数组,再将排序好的子数组合并为排序好的长数组。 +- 动态规划也是将原问题分解为多个子问题,但与分治算法的主要区别是,**动态规划中的子问题往往不是相互独立的**,原问题的解依赖于子问题的解,而子问题的解又依赖于更小的子问题的解。因此,动态规划通常会引入记忆化,保存已经解决的子问题的解,避免重复计算。 +- 回溯算法在尝试和回退中穷举所有可能的解,并通过剪枝避免不必要的搜索分支。原问题的解由一系列决策步骤构成,我们可以将每个决策步骤之后的剩余问题看作为一个子问题。