This commit is contained in:
krahets
2023-08-27 23:40:56 +08:00
parent 48980ddf28
commit df0f7d3be1
64 changed files with 255 additions and 261 deletions

View File

@@ -367,7 +367,7 @@ status: new
我们可以尝试从问题分解的角度分析这道题。设爬到第 $i$ 阶共有 $dp[i]$ 种方案,那么 $dp[i]$ 就是原问题,其子问题包括:
$$
dp[i-1] , dp[i-2] , \dots , dp[2] , dp[1]
dp[i-1], dp[i-2], \dots, dp[2], dp[1]
$$
由于每轮只能上 $1$ 阶或 $2$ 阶,因此当我们站在第 $i$ 阶楼梯上时,上一轮只可能站在第 $i - 1$ 阶或第 $i - 2$ 阶上。换句话说,我们只能从第 $i -1$ 阶或第 $i - 2$ 阶前往第 $i$ 阶。
@@ -384,10 +384,7 @@ $$
<p align="center"> 图 14-2 &nbsp; 方案数量递推关系 </p>
我们可以根据递推公式得到暴力搜索解法
- 以 $dp[n]$ 为起始点,**递归地将一个较大问题拆解为两个较小问题的和**,直至到达最小子问题 $dp[1]$ 和 $dp[2]$ 时返回。
- 最小子问题的解 $dp[1] = 1$ , $dp[2] = 2$ 是已知的,代表爬到第 $1$ , $2$ 阶分别有 $1$ , $2$ 种方案。
我们可以根据递推公式得到暴力搜索解法。以 $dp[n]$ 为起始点,**递归地将一个较大问题拆解为两个较小问题的和**,直至到达最小子问题 $dp[1]$ 和 $dp[2]$ 时返回。其中,最小子问题的解是已知的,即 $dp[1] = 1$、$dp[2] = 2$ ,表示爬到第 $1$、$2$ 阶分别有 $1$、$2$ 种方案。
观察以下代码,它和标准回溯代码都属于深度优先搜索,但更加简洁。
@@ -617,10 +614,10 @@ $$
## 14.1.2 &nbsp; 方法二:记忆化搜索
为了提升算法效率,**我们希望所有的重叠子问题都只被计算一次**。为此,我们声明一个数组 `mem` 来记录每个子问题的解,并在搜索过程中这样做:
为了提升算法效率,**我们希望所有的重叠子问题都只被计算一次**。为此,我们声明一个数组 `mem` 来记录每个子问题的解,并在搜索过程中将重叠子问题剪枝。
1. 当首次计算 $dp[i]$ 时,我们将其记录至 `mem[i]` ,以便之后使用。
2. 当再次需要计算 $dp[i]$ 时,我们便可直接从 `mem[i]` 中获取结果,从而将重叠子问题剪枝
2. 当再次需要计算 $dp[i]$ 时,我们便可直接从 `mem[i]` 中获取结果,从而避免重复计算该子问题。
=== "Java"
@@ -1163,10 +1160,10 @@ $$
与回溯算法一样,动态规划也使用“状态”概念来表示问题求解的某个特定阶段,每个状态都对应一个子问题以及相应的局部最优解。例如,爬楼梯问题的状态定义为当前所在楼梯阶数 $i$ 。
总结以上,动态规划的常用术语包括:
根据以上内容,我们可以总结出动态规划的常用术语
- 将数组 `dp` 称为「$dp$ 表」,$dp[i]$ 表示状态 $i$ 对应子问题的解。
- 将最小子问题对应的状态(即第 $1$ , $2$ 阶楼梯)称为「初始状态」。
- 将最小子问题对应的状态(即第 $1$ $2$ 阶楼梯)称为「初始状态」。
- 将递推公式 $dp[i] = dp[i-1] + dp[i-2]$ 称为「状态转移方程」。
## 14.1.4 &nbsp; 空间优化