动态规划

动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题 -----baidu

动态规划题目特点:

类型1.计数
有多少种方式走到右下角
有多少种方法选出k个数使得和是Sum

类型2.求最大最小值
从左上角走到右下角路径的最大数字和
最长上升子序列长度

3.求存在性
取石子游戏,先手是否必胜
能不能选出k个数使得和是Sum

在这里插入图片描述
在这里插入图片描述
动态规划组成部分一:确定状态:
状态在动态规划中的作用属于定海神针,简单的说,解动态规划的时候需要开一个数组 ,数组的每个元素fi]或者f[i][j]代表什么,类似于解数学题中, X, Y , Z代表什么。
确定状态需要两个意识:
-最后一步
-子问题
那什么是最后一步:
虽然我们不知道最优策略是什么,但是最优策略肯定是K枚硬币a1, a2,a3…ak面值加起来是27
所以一定有一枚最后的硬币: ak,除掉这枚硬币,前面硬币的面值加起来是27- ak
在这里插入图片描述
关键点1
我们不关心前面的K-1枚硬币是怎么拼出27-ak的(可能有1种拼法,可能有100种拼法),而且我们现在甚至还不知道ak和K,但是我们确定前面的硬币拼出了27-ak。
关键点2
因为是最优策略,所以拼出27-aK的硬币数一定要最少,否则这就不是最优策略了

子问题
所以我们就要求:最少用多少枚硬币可以拼出27- a
为了简化定义,我们设状态f(X)=最少用多少枚硬币拼出X

最后那枚硬币ak只可能是2 , 5或者7
如果a是2 , f(27)应该是f(27-2)+ 1 (加上最后这一枚硬币2 )
如果a是5 , f(27)应该是f(27-5)+ 1 (加_上最后这一枚硬币5 )
如果ax是7 , f(27)应该是f(27-7)+ 1 (加上最后这一枚硬币7 )
除此以外,没有其他的可能了。
需要求最少的硬币数,所以:
在这里插入图片描述
递归解法

int f(int X) {
	if(X == 0) return 0; .
	int res = MAX VALUE;
	if(X>=2){
	res = Math.min(f(X- 2)+ 1, res); .
	}
	if(X>= 5){
	res = Math.min(f(X- 5) + 1, res);
	}
	if(X>= 7){
	res = Math.min(f(X- 7) + 1, res);
	}
return res;
}	

递归解法的缺点是有很多重复计算
在这里插入图片描述
以10为例:
在这里插入图片描述
动态规划组成部分二:转移方程
设状态f[X]=最少用多少枚硬币拼出X,对于任意的X,都有:

f[X] = min{f[X-2]+1, f[X-5]+1, f[X-7]+1}

动态规划组成部分三:初始条件和边界情况
两个问题: X-2, X-5或者X-7小于0怎么办?什么时候停下来? 如果不能拼出Y ,就定义f[Y]=正无穷
-例如f[-1]=f[-2]=…=正无穷
所以f1] =min{f[-1]+1, f[-4]+1,f[-6]+1}=正无穷,表示拼不出来1
初始条件: f[0]= 0
然后计算f[1], f[2], … f[27]
当我们计算到f[X]时, f[X-2], f[X-5], f[X-7]都已经得到结果了

在这里插入图片描述
计算顺序f[0],f[1], f[2],f[3] … f[27]
上代码:

public int coinChange(intD A, int M) {

int[]f = new int[M + 1];
int n = A.length;
f[0] = 0;   //初始
int i, j;
for(i=1;i<=M;++i){     // f[1], f[2], ... f[27]
	f[i]= Integer.MAX_VALUE;
	for(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) {
fDM] = -1;
}
return f[M];
}
}

leetcode:不同路径
计数型动态规划
在这里插入图片描述
动态规划组成部分一: 确定状态
最后一步:无论机器人用何种方式到达石下角,总有最后挪动的一步:向右或者向下
右下角坐标设为(m-1, n-1)那么前一步机器人一定是在(m-2, n-1 )或者(m-1, n-2)
在这里插入图片描述
子问题:
那么,如果机器人有X种方式从左上角走到(m-2,n-1) ,有Y种方式从左上角走到(m-1 ,n-2) ,则机器人有X+Y种方式走到(m-1, n-1)问题转化为,机器人有多少种方式从左上角走到(m-2, n-1)和(m-1, n-2)
3原题要求有多少种方式从左上角走到(m-1, n-1)
状态:设f[i][j]为机器人有多少种方式从左上角走到(i, j)
转移方程:
在这里插入图片描述
动态规划组成部分三:初始条件和边界情况
初始条件: f[0][0]= 1 ,因为机器人只有一-种方式到左上角
边界情况: i=0或j=0 ,则前一步只能有一个方向过来->f[i][j]= 1
计算顺序:
●f[0][0]= 1
计算第0行: f[O][0], f[0][1], … f[0][n-1]
计算第1行: f[1][0], f[1][1], … f[1][n-1]
计算第m-1行: f[m-1][0], f[m-1][1], … f[m-1][n-1]
答案是f[m-1][n-1]

public int uniquePaths(int m, int n) {
int[]f = new int[m][n];
int i, j;
for(i=0;i<m;++i){
	for(j=0;j<n;++j){
		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];
}
}

跳跃游戏
存在型动态规划
有n块石头分别在x轴的0, 1, … n-1位置一只青蛙在石头0 ,想跳到石头n-1如果青蛙在第i块石头.上,它最多可以向右跳距离a;问青蛙能否跳到石头n-1
例子:
输入: a=[2,3,1, 1, 4]
输出: True
输入: a=[3,2, 1,0, 4]
输出: False

动态规划组成部分一:确定状态
最后一步:如果青蛙能跳到最后-块石头n-1 ,我们考虑它跳的最后一步
这一步是从石头i跳过来, i<n-1
这需要两个条件同时满足:
-青蛙可以跳到石头i
-最后一步不超过跳跃的最大距离: n-1-i<=a;
在这里插入图片描述
那么,我们需要知道青蛙能不能跳到石头i (i<n-1),而我们原来要求青蛙能不能跳到石头n-1,由此引导出我们的子问题:
状态:设f[j]表示青蛙能不能跳到石头j
转移方程:
在这里插入图片描述
动态规划组成部分三:初始条件和边界情况
初始条件: f[0]= True ,因为青蛙一 开始就在石头0

动态规划组成部分四:计算顺序
设fj]表示青蛙能不能跳到石头j
●初始化f[0]=True
●计算f[1], f[2], … f[n-1]
●答案是f[n-1]
●时间复杂度: O(N2) ,空间复杂度(数组大小) : O(N)

public boolean canJump(int[]A) {
int n = A.length;
boolean口] f = new boolean[n];
f[0] = true; 
for(intj=1;j<n;++j){
	f[j] = false;
	for(inti=0;i<j;++i){
		if (f[i] &i+ A[i]>=j) {
			f[j] = true;
			break;
		}
	}
}
return f[n - 1];
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值