动态规划

题型一:
打家劫舍
在这里插入图片描述

思路:
递归:
当我们计算如果有n家可以偷的房屋时,我们从最后一家开始看起,偷最后一家后的最大金额考虑是:
1.我们偷第n家,这时第n-1家不可以偷,所以最大金额是前n-2家最大的值加上第n家的金额。
2.我们不偷第n家,这时第n-1家可以偷,所以最大金额就是前n-1家能偷的最大值。

边界条件是:
1.一家都没有,返回0。
2.有一家能偷,返回此家能偷的钱。
3.有两家能偷,返回这两家最大的钱。

代码:

var rob = function(nums) {
    function cal(n){
    if(n==0)return 0;
    if(n==1)return nums[0];
    if(n==2)return Math.max(nums[0],nums[1]);
    if(n>2)return Math.max(cal(n-1),cal(n-2)+nums[n-1]);
}
    return cal(nums.length);

};

代码是我自己写的,很不幸的是它超时了。。。
在这里插入图片描述

这时我们来看官方给出的答案:

class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int length = nums.length;
        if (length == 1) {
            return nums[0];
        }
        int[] dp = new int[length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < length; i++) {
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[length - 1];
    }
}

官方没有JS的答案,不过思路都是一样的,就是用一个数组来保存状态从而避免递归的使用。
所以我重写了一下:

var rob = function(nums) {
    if(nums.length == 0||nums==null)return 0;
    if(nums.length == 1) return nums[0];
    var dp = new Array();
    dp[0] = nums[0];
    dp[1] = Math.max(nums[0],nums[1]);
    for(let i = 2;i<nums.length;i++){
        dp[i] = Math.max(nums[i]+dp[i-2],dp[i-1]);
    }
    return dp[nums.length-1];
};

结果:
在这里插入图片描述

题型二:
三角形最小路径和
在这里插入图片描述

思路:
遍历行列,计算每个数据的最小路径,用二维数组记录,通过动态规划来得到最小值。最后再遍历一遍最后一行的数据,把最小的值返回。和上一题思路差不多,不过动用到二维数组相对复杂一点。

var minimumTotal = function(triangle) {
    if(triangle.length==0||triangle==null)return 0;
    if(triangle.length == 1)return triangle[0][0];
    let length = triangle.length;
     let len = triangle.length
  	 let len2 = triangle[len - 1].length
 		 let dp = new Array(len).fill('').map(item => new Array(len2))//创建二维数组
    dp[0][0] = triangle[0][0];
    dp[1][0] = dp[0][0]+triangle[1][0];
    dp[1][1] = dp[0][0]+triangle[1][1];
    for(let i = 2;i<length;i++){
        dp[i][0] = dp[i-1][0]+triangle[i][0];//计算第一个的dp
        for(let j = 1;j<i;j++){
            dp[i][j] = Math.min(dp[i-1][j]+triangle[i][j],dp[i-1][j-1]+triangle[i][j]);
        }
        dp[i][i] = dp[i-1][i-1]+triangle[i][i];//计算最后一个的dp
    }
    var out = dp[length-1][0];
    for(let i =1;i<dp[length-1].length;i++){
        out = Math.min(out,dp[length-1][i]);
    }
    return out;
};

提交结果:
在这里插入图片描述

这个结果明显很差劲啊,我们来看看更好的解法。

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        vector<int> dp(triangle.back());
        for(int i = triangle.size() - 2; i >= 0; i --)
            for(int j = 0; j <= i; j ++)
                dp[j] = min(dp[j], dp[j + 1]) + triangle[i][j];
        return dp[0];
    }
};

这是自下而上的算法,triangle.back是取triangle最后一行来给dp初始化的,通过遍历,最小的数值最终会落到dp[0]里面。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值