动态规划入门学习
本文根据bilibili动态规划视频整理而来
动态规划题目特点
1.计数
2.求最值
3.存在性问题(是否、01、yes no)
例题讲解一
问题描述
思考过程
最优的策略,最后一个去掉后,剩下的也要是最优,也就是求子问题的最优
通过i找最优的子问题的解的问题,都可以用动态规划去解
最终可以得到下面的式子
解法
递归解法
存在的问题
重复的计算较多,最终的复杂度大大增加,最严重的问题是会超时,我们需要一个会将结果保存下来的算法
动态规划解法
转移方程
一般在面试的时候写出转移方程,那解题过程就会显得更加完美
初始条件和边界情况
但是我们仍然要考虑两个重要的组成部分:初始条件和边界情况
注意:初始条件有时候是不需要的,如果转移方程算不出来的但是有需要的定义,那就是作初始条件
其实初始条件就是最小的值,边界情况就是不要数组越界(正负越界)
计算顺序
大部分动规问题可以从小到大计算(即子问题先于父问题求解),其实就是求解一个数组的每一个值
程序
public class Solution {
//{2,5,7} //27
public static int coinChange(int[] A, int M){
//首先在不浪费空间的基础上开辟空间
int[] f = new int[M + 1];
int n = A.length;
f[0] = 0;
int i,j;
// f[1], f[2],......,f[27]
for (i = 1; i <= M; ++i){
f[i] = Integer.MAX_VALUE; //先暂定无穷大
//f[i] = min{f[i-A[0]]+1,......,f[i-A[n-1]]+1}
for (j = 0; j < n; ++j){ //对每一钟结果都算一遍
//避免i-A[i]是负数, 避免在计算机层面上越界
if (i >= A[j] && f[i - A[j]] != Integer.MAX_VALUE){
f[i] = Math.min(f[i - A[j]] + 1, f[i]);
}
}
}
//如果最后结果出不来,就返回-1
if (f[M] == Integer.MAX_VALUE){
f[M] = -1;
}
return f[M];
}
public static void main(String[] args) {
int[] A ={2, 5, 7};
int M = 27;
System.out.println(coinChange(A,M));
}
}
例题讲解二
问题描述:
解法
确定状态
注意,关于在算法中开辟空间维度的问题,题目的子问题要求解决多少个变量,就开几维
转移方程
初始条件和边界情况
这道题地边界情况是对于某一维为0的情况来说的
注意边界情况f【i】【j】 = 1,因为在边界的时候,只有一个方向能过来,所以就赋值1,而其他的情况,就有两种可能,所以要把两种可能相加(这个时候就要注意题意了,是说有多少种可能,而不是要走过多少个格子)
计算顺序
程序
public class Solution2 {
public static int uniquePaths(int m, int n){
int[][] f = new int[m][n]; // 注意这里就不像上一题要+1
int i,j;
for (i = 0; i < m; ++i){ // row: top to bottom
for (j = 0; j < n; ++j){ // column: left to right
if (i == 0 || j == 0){
f[i][j] = 1;
} else {
f[i][j] = f[i - 1][j] + f[i][j - 1];
}
}
}
return f[m - 1][n - 1];
}
public static void main(String[] args) {
System.out.println(uniquePaths(7, 3));
}
}
例题讲解三
解法
确定状态
找到子问题
转移方程
上面的OR表示只要有一个i满足括号内的条件,那这个整体就为真
初始条件和边界情况
这道题没有边界情况,因为枚举的i不会越界
计算顺序
程序
public class Solution3 {
public static boolean canJump(int[] A){
int n = A.length;
boolean[] f = new boolean[n];
f[0] = true;
for (int j = 1; j < n; ++j){
f[j] = false;
//对已经求出来得f[i]遍历,直到满足条件确定可以跳到f[j]为止
for (int i = 0; i < j; ++i){
if (f[i] && i + A[i] >= j){
f[j] = true;
break;
}
}
}
return f[n-1];
}
public static void main(String[] args) {
int[] A = {2,3,1,1,4};
System.out.println(canJump(A));
}
}