深入理解动态规划DP
2016-04-16 12:38
246 查看
通过最近对于一些算法题的思考,越来越发现动态规划方法的在时间上高效性,往往该问题可以轻松的找到暴力破解的方法,其时间复杂度却不尽人意。下面来看看几个常见的动态规划思路的经典问题
例一.有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?(腾讯电面题之一)
其状态转移方程为:
f(n):表示n阶楼梯有多少种走法f(n):表示n阶楼梯有多少种走法f(n)=f(n−1)+f(n−2) f(n) =f(n-1)+f(n-2)f(1)=1,f(2)=2f(1)=1,f(2)=2
例二:01背包问题
有n个重量和价值分别为vector weight, vector value的物品;背包最大负重为W,求能用背包装下的物品的最大价值?
输入:n =4
weight=2, 1, 3, 2
value =3, 2, 4, 2
W=5
输出=7
dp[i][j]表示前i号物品中能选出重量在j之内的最大价值dp[i][j]表示前i号物品中能选出重量在j之内的最大价值dp[i][j]=max(dp[i−1][j],dp[i−1][j−w[i]]+v[i]);dp[i][j] = max(dp[i-1][j] , dp[i-1][j-w[i]] + v[i]);
例三:最大连续子序列和
如给定数组[-2,1,-3,4,-1,2,1,-5,4]
连续的子数组为[4,-1,2,1]有最大和6
f(j+1)为以下标j结尾的连续子序列和的最大值f(j+1)为以下标j结尾的连续子序列和的最大值f(j+1)=max(f(j)+A[j],A[j])f(j+1)=max(f(j)+A[j],A[j])target=maxf[j]target = max{f[j]}
思考:最大连续子序列乘积
如给定数组[-2,1,-3,4,-1,2,1,-5,4]
连续的子数组为[4,-1,2,1]有最大和6
f(j+1)为以下标j结尾的连续子序列最大乘积值(1)f(j+1)为以下标j结尾的连续子序列最大乘积值(1)
状态转移方程如何表示呢:
这里我们知道A[j]可能为正数(或0)或负数,那么当A[j]为正数,期望前j个乘积为正数,若为负数,则期望前面的为负数。故我们需定义两个函数来确定我们的状态转移方程:
fmax(j+1)=max(max(fmax(j)∗A[j],A[j]),fmin(j)∗A[j])fmax(j+1)=max( max(fmax(j)*A[j],A[j]),fmin(j)*A[j] )fmin(j+1)=min(min(fmin(j)∗A[j],A[j]),fmax(j)∗A[j])(2)fmin(j+1)=min(min(fmin(j)*A[j],A[j]),fmax(j)*A[j] )(2)
1.通过以上动态问题问题的分析,可以看出最重要的是定义好相应的问题,然后写出状态转移方程,往往这也是整个问题求解最能考察你分析能力的过程。能够用动态规划求解的问题有两类性质:
a.重叠子问题
采用递推方式,比如上例要求出10阶楼梯走法,那么最后一步是踏一步上来或者踏2步上来,最后转化为相应的子问题,子问题深入求解就包含了重叠的子问题,所以自顶向下的实现并不高效,常采用备忘录方式保存子问题的最优解,自底向上更高效。
b.最优子结构:
往往子问题的最优解可以推出原问题的最优解
例一.有一段楼梯有10级台阶,规定每一步只能跨一级或两级,要登上第10级台阶有几种不同的走法?(腾讯电面题之一)
其状态转移方程为:
f(n):表示n阶楼梯有多少种走法f(n):表示n阶楼梯有多少种走法f(n)=f(n−1)+f(n−2) f(n) =f(n-1)+f(n-2)f(1)=1,f(2)=2f(1)=1,f(2)=2
例二:01背包问题
有n个重量和价值分别为vector weight, vector value的物品;背包最大负重为W,求能用背包装下的物品的最大价值?
输入:n =4
weight=2, 1, 3, 2
value =3, 2, 4, 2
W=5
输出=7
dp[i][j]表示前i号物品中能选出重量在j之内的最大价值dp[i][j]表示前i号物品中能选出重量在j之内的最大价值dp[i][j]=max(dp[i−1][j],dp[i−1][j−w[i]]+v[i]);dp[i][j] = max(dp[i-1][j] , dp[i-1][j-w[i]] + v[i]);
例三:最大连续子序列和
如给定数组[-2,1,-3,4,-1,2,1,-5,4]
连续的子数组为[4,-1,2,1]有最大和6
f(j+1)为以下标j结尾的连续子序列和的最大值f(j+1)为以下标j结尾的连续子序列和的最大值f(j+1)=max(f(j)+A[j],A[j])f(j+1)=max(f(j)+A[j],A[j])target=maxf[j]target = max{f[j]}
思考:最大连续子序列乘积
如给定数组[-2,1,-3,4,-1,2,1,-5,4]
连续的子数组为[4,-1,2,1]有最大和6
f(j+1)为以下标j结尾的连续子序列最大乘积值(1)f(j+1)为以下标j结尾的连续子序列最大乘积值(1)
状态转移方程如何表示呢:
这里我们知道A[j]可能为正数(或0)或负数,那么当A[j]为正数,期望前j个乘积为正数,若为负数,则期望前面的为负数。故我们需定义两个函数来确定我们的状态转移方程:
fmax(j+1)=max(max(fmax(j)∗A[j],A[j]),fmin(j)∗A[j])fmax(j+1)=max( max(fmax(j)*A[j],A[j]),fmin(j)*A[j] )fmin(j+1)=min(min(fmin(j)∗A[j],A[j]),fmax(j)∗A[j])(2)fmin(j+1)=min(min(fmin(j)*A[j],A[j]),fmax(j)*A[j] )(2)
1.通过以上动态问题问题的分析,可以看出最重要的是定义好相应的问题,然后写出状态转移方程,往往这也是整个问题求解最能考察你分析能力的过程。能够用动态规划求解的问题有两类性质:
a.重叠子问题
采用递推方式,比如上例要求出10阶楼梯走法,那么最后一步是踏一步上来或者踏2步上来,最后转化为相应的子问题,子问题深入求解就包含了重叠的子问题,所以自顶向下的实现并不高效,常采用备忘录方式保存子问题的最优解,自底向上更高效。
b.最优子结构:
往往子问题的最优解可以推出原问题的最优解
相关文章推荐
- LCS最长公共子序列
- java.lang.NoClassDefFoundError: android.support.v7.internal.widget.TintManager 解决办法
- Shell 命令行快捷键
- 《Linux内核与分析》第八周
- java基础(五),接口
- 【UNET自学日志】Part3 变得更有效率一点
- mybatis实战教程(mybatis in action),mybatis入门到精通
- 最小年龄的3个职工
- 仓库添加jar包
- linux svn环境搭建
- 【学习日记】ROS下IMU使用困惑
- JDK自带工具一览表
- (水)POJ-1416 DFS技巧
- 面向对象编程的基本原则
- 背包问题(贪心法)
- 【风马一族_构思】寻找二点间的最短距离
- U3D DrawCall优化手记
- ViewPager的用法
- 词袋模型BoW图像检索Python实战
- OC与Swift混编