定义
How should I explain dynamic programming to a 4-year-old?
writes down “1+1+1+1+1+1+1+1 =” on a sheet of paper
“What’s that equal to?”
counting “Eight!”
writes down another “1+” on the left
“What about that?”
quickly “Nine!”
“How’d you know it was nine so fast?”
“You just added one more”
“So you didn’t need to recount because you remembered there were eight!Dynamic Programming is just a fancy way to say ‘remembering stuff to save time later’”
动态规划题目特点
- 计数
- 有多少种方式走到右下角
- 有多少种方法选出k个数使得和是
sum
- 求最大最小值
- 从左上角走到右下角路径的最大数字和
- 最长上升子序列长度
- 求存在性
- 取石子游戏,先手是否必胜
- 能不能选出k个数使得和是
sum
动态规划的组成
例题
你有三种硬币,分别面值2元、5元和7元,每种硬币足够多。
买一本书需要27元。
如何用最少的硬币组合正好付清,不需要对方找钱。
- 确定状态
- 状态在动态规划中的作用属于定海神针
- 解动态规划的时候需要开一个数组,数组的每个元素代表什么。
- 确定状态需要两个意识:
- 最后一步:最后一枚硬币ak,除掉这枚硬币前面的硬币面值加起来是27-ak
- 子问题:最少用多少枚硬币可以拼出27-ak
- 和递归的区别:将计算结果保存下来,并改变计算顺序
-
转移方程
- 设状态f[X] = 最少用多少枚硬币拼出X
- 对于任意X,f[X] = min{f[X-2] + 1, f[X-5] + 1, f[X-7] + 1}
-
初始条件和边界情况
- 如果拼不出Y,就定义f[Y] = 正无穷
- 初始条件:f[0] = 0
-
计算顺序
- 当我们计算到f[X]时,f[X-2], f[X-5], f[X-7]都已经得到结果了
- 算法时间复杂度:27*3
Let’s TRY
Description
You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return-1
.
Answer
public class Solution {
public int coinChange(int[] A, int M){
int[] f = new int[M + 1];
int n = A.length;
//initialization
f[0] = 0;
int i, j;
//f[1], f[2], ..., f[27]
for (int i = 1; i <= M; i++) {
f[i] = Integer.MAX_VALUE;
//last coin
for (int j = 0; j < n; j++) {
if (i >= A[j] && f[i - A[j]] != Integer.MAX_VALUE) {
f[i] = Math.min(f[i - A[j]] + 1, f[i]);
}
}
}
if (f[M] == Integer.MAX_VALUE) {
f[M] = -1;
}
return f[M];
}
}