动态规划总结一

主要是跟着GitHub项目https://github.com/youngyangyang04/leetcode-master进行刷题系统性学习,从这一篇开始进行总结自己的动态规划刷题心得

定义

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的,


学习内容:

做动态规划题目的时候,模糊会做了一些题目,但是题目稍微换一下加深难度又找不到思路,不会如何解题了。
参考总结出动态规划解题的几个步骤:
1.确定dp数组的下标以及定义
2.确定递推公式
3.dp数组如何初始化
4.确定遍历顺序
5.举例推导dp数组
动态规划题目写代码时候出现问题是很正常的事情,出问题的时候要从以下:dp数组定义问题,dp递推公式问题,dp数组的初始化问题三个方面进行考虑,而定位一个动态规划代码问题出现在哪里的最好方式就是举一个例子,先进行手动递推公式演算过程,如果和预想答案不一样那么递推公式本身就已经错误了,自然代码也写错了。然后就是将代码过程进行输出,查看是哪一步出现了不同,然后再反推回代码出错的地方就能比较清晰的解决动态规划写错的问题了。


先从一些入门的leetcode题目进行总结这个过程吧。

746:使用最小花费爬楼梯

题目:
https://leetcode-cn.com/problems/min-cost-climbing-stairs/
数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。

每当你爬上一个阶梯你都要花费对应的体力值,一旦支付了相应的体力值,你就可以选择向上爬一个阶梯或者爬两个阶梯。

请你找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。
官方例子:
输入:cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出:6
解释:最低花费方式是从 cost[0] 开始,逐个经过那些 1 ,跳过 cost[3] ,一共花费 6 。

解题流程:
首先题目中选择想上爬一个或者两个楼梯这里就可以看出是利用动态规划
1.假设dp[i]表示到第i个楼梯所经历的过程(第一步确定dp数组的下标以及定义)
2.我们先简化来看不去考虑花费问题,那么到达dp[i] = dp[i-1]爬一步楼梯到达或者dp[i-2]爬两步楼梯到达;加上花费问题之后dp[i] = Math.min(dp[i-1],dp[i-2])+cost[i];(第二步确定递推公式)
3.确定完递推公式之后就要考虑初始化问题,因为这个递推公式需要两个变量,所以真正开始进行递推循环是从第三个楼梯开始的。写代码习惯上从0开始计算。
第一楼梯dp[0] = cost[0];
第二楼梯dp[1] = cost[1];
第三楼梯开始递推dp[2] = Math.min(dp[1],dp[0])+cost[2]
(第三步初始化)
4.接着就是写代码进行遍历递推了,我们看到遍历顺序是从前往后进行遍历的(第四步)
5.举个例子进行验证(第五步)

这一题其实跟斐波那契数列类似f[i] = f[i-1]+f[i-2];
代码:
版本一:

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        if(cost.length<=2){
            return cost[cost.length-1];
        }
        int[] f = new int[cost.length];
        f[0] = cost[0];
        f[1] = cost[1];
        for(int i=2;i<cost.length;i++){
            f[i]=Math.min(f[i-1],f[i-2])+cost[i];
        }
        return f[i];
    }
}

版本二:

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        if(cost.length<=2){
            return cost[cost.length];
        }
        int one=cost[1],two=cost[0];
        for(int i=2;i<cost.length;i++){
            int count = one;
            one=Math.min(one+cost[i],two+cost[i]);
            two = count;
        }
        return Math.min(one,two);
    }
}

62:不同路径

https://leetcode-cn.com/problems/unique-paths/

题目:
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?
官方例子:
输入:m = 3, n = 7
输出:28

解题思路:
首先是机器人每次只能向下或者向右移动一步这里可以看出利用动态规划
1.假设dp[i][j]表示从起始到i行j列所进行的路径。(第一步)
2.然后是考虑dp[i][j]怎么来,机器人只能向下或者向右步行,所以dp[i][j] = 上面向下步行dp[i-1][j]加上左边向右步行dp[i][j-1]。dp[i][j] =dp[i-1][j]+dp[i][j-1]。(第二步)
3.接着是考虑初始化问题,在第0行路径上都只有向右走一条路径,所以初始化为1,在第0列路径上也同样是只有向下走一条路径,所以初始化为1。(第三步)。
4.初始化完成之后考虑遍历顺序,因为要输出右下节点的路径,所以每个节点都要考虑,从前往后进行遍历所有节点。
5.举个例子进行验证。
代码:

public int uniquePaths(int m, int n) {
        int[][] arr = new int[m][n];
        for(int i=0;i<m;i++){
            arr[i][0] = 1;
        }
        for(int i=0;i<n;i++){
            arr[0][i] = 1;
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                arr[i][j] = arr[i-1][j]+arr[i][j-1];
            }
        }
        return arr[m-1][n-1];
    }

其实这道题目还有数学公式解法:

/**public int uniquePaths(int m, int n) {
        long num = 1;
        for(int i=n,j=1;j<m;j++,i++){
            num = num*i/j;
        }
        return (int)num;
    }*/

但主要总结动态规划问题解题思路,所以不进行介绍了,官方题解有解释。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值