目录
1、动态规划简介
动态规划(Dynamic Programming, DP)是运筹学的一个分支,用于求解最优化问题。
在解决问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法(自底向上)正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解。
动态规划算法,一般包含以下几个主要步骤:
- 状态表示:dp表中的值所表示的含义。一般由 经验+题目要求 得出。对于一维的dp表,dp[i]通常有这两种表示形式(由经验得出):①:以i位置为结尾,......;②:以i位置为起点,......;而....就是需要结合题目来得出的。
- 状态转移方程:就是dp[i]是怎么来的。dp[i]通常由其相邻的其他状态经过公式计算得出,状态转移方程就是这个公式。
- 初始化:确保在填dp表的过程中不越界。
- 填表顺序:为了在填写当前状态的时候,所需要的其他相邻状态已经计算得出了。
- 返回值:结合题目要求。
在此过程中,我认为确定状态表示是最重要的一点,而确定状态转移方程是最难的一点。
2、算法实战应用【leetcode】
2.1 题一:第N个泰波那契数
2.1.1 算法原理
对于一维dp,状态表示通常由 经验+题目要求 得出,本题很明显,表示第i个泰波那契数的值;同时状态转移方程题目也是贴心的给出了。
- 状态表示dp[i]:第i个泰波那契数的值
- 状态转移方程:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
- 初始化:dp[0] = 0; dp[1] = dp[2] = 1;
- 填表顺序:从左往右
- 返回值:dp[n]
2.1.2 算法代码
class Solution {
public int tribonacci(int n) {
if(n == 0) return 0;
if(n == 1 || n == 2) return 1;
int[] dp = new int[n + 1];
dp[0] = 0; dp[1] = dp[2] = 1;
for(int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
}
return dp[n];
}
}
2.1.3 空间优化原理——滚动数组
实际上,我们可以不用创建一个dp数组来存储数值,
通过“滚动数组”的方式,进行空间优化。
仅仅使用三个变量就可以解题,不必再开辟额外的空间。
2.1.4 算法代码——空间优化版本
class Solution {
public int tribonacci(int n) {
//动态规划 -> 空间优化
if(n == 0) return 0;
if(n == 1 || n == 2) return 1;
int a = 0, b = 1, c = 1, d = 0;
for(int i = 3; i <= n; i++) {
d = a + b + c;
//滚动操作
a = b;
b = c;
c = d;
}
return d;
}
}