一维动态规划
动态规划(Dynamic Programming,简称 DP)是一种用于解决复杂问题的算法设计技术。它通过将问题分解为更小的子问题,并存储这些子问题的解,从而避免重复计算,提高效率。一维动态规划是动态规划中最基础的形式,通常用于解决只需要一个一维数组来存储状态的问题。
什么是动态规划?
动态规划的核心思想是分治和记忆化。它将一个大问题分解为多个重叠的子问题,通过解决这些子问题来构建原问题的解。为了避免重复计算,动态规划会将这些子问题的解存储起来,以便在需要时直接使用。
动态规划的适用条件
- 最优子结构:问题的最优解可以通过子问题的最优解来构造。
- 重叠子问题:在解决问题的过程中,相同的子问题会被多次计算。
一维动态规划的基本结构
一维动态规划通常使用一个一维数组来存储子问题的解。这个数组的每个元素代表一个子问题的解,通过逐步填充这个数组,最终得到原问题的解。
基本步骤
- 定义状态:确定问题的状态,并用一个一维数组来表示这些状态。
- 状态转移方程:找到状态之间的关系,即如何从一个状态转移到另一个状态。
- 初始化:确定初始状态的值。
- 计算顺序:按照一定的顺序计算状态数组中的每个元素。
- 返回结果:从状态数组中提取最终的解。
示例:斐波那契数列
斐波那契数列是一个经典的动态规划问题。斐波那契数列的定义如下:
- F(0) = 0
- F(1) = 1
- F(n) = F(n-1) + F(n-2) (n ≥ 2)
代码实现
python
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
dp = [0] * (n + 1)
dp[0] = 0
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[n]
输入与输出
- 输入:
n = 5
- 输出:
5
备注
在这个例子中,我们使用一个一维数组 dp
来存储斐波那契数列的值。通过逐步计算 dp[i]
,我们最终得到了 F(5)
的值。
实际应用:爬楼梯问题
假设你正在爬楼梯,每次你可以爬 1 阶或 2 阶。问:有多少种不同的方法可以爬到第 n
阶?
分析
这个问题可以转化为斐波那契数列问题。设 dp[i]
表示爬到第 i
阶的方法数,那么:
dp[0] = 1
(表示在地面,只有一种方法)dp[1] = 1
(只有一种方法爬到第 1 阶)dp[i] = dp[i-1] + dp[i-2]
(可以从第i-1
阶爬 1 阶,或者从第i-2
阶爬 2 阶)
代码实现
python
def climb_stairs(n):
if n == 0:
return 1
elif n == 1:
return 1
dp = [0] * (n + 1)
dp[0] = 1
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[n]
输入与输出
- 输入:
n = 3
- 输出:
3
提示
在这个问题中,我们再次使用了一维动态规划的思想。通过存储子问题的解,我们避免了重复计算,大大提高了效率。
总结
一维动态规划是动态规划中最基础的形式,适用于许多只需要一个一维数组来存储状态的问题。通过定义状态、状态转移方程、初始化和计算顺序,我们可以有效地解决许多复杂的问题。
附加资源
练习
- 编写一个函数,计算第
n
个斐波那契数。 - 解决爬楼梯问题,假设每次可以爬 1 阶、2 阶或 3 阶。
- 尝试解决其他一维动态规划问题,如“最大子数组和”问题。
通过不断练习,你将更好地掌握一维动态规划的思想和应用。