力扣——打家劫舍 从问题出发了解动态规划


动态规划

算法部分最常见的方法之一


一、动态规划是什么?

动态规划是算法部分最常见的方法之一,很多问题都可以用动态规划去解决或管理。而如何使用动态规划就成为了新手程序员进阶略有经验的程序员的一道门槛。对于动态规划来说,他不是一种简单的方法或者一种函数,而是一种思想。(我已于百度达成了合作协议,具体定义可以去百度方面咨询

二、动态规划的三个步骤

  • 研究明白:最后一个情况可以由哪些情况达到?
  • 向前推导,直到推导到第一步
  • 研究明白第一或者前几个已知的情况如何构成后面的情况。

这三个步骤来说,第一步是找出解决方案,而最后一步是让自己相信自己的解决方案是对的
我 骗 我 自 己

三、力扣经典题——打家劫舍

我们从一道经典问题出发来帮助我们理解这个说法:

		LeetCode#198 打家劫舍
		
		你是一个专业的小偷,计划偷窃沿街的房屋。
	    每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,
	 	如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
	 	
		给定一个代表每个房屋存放金额的非负整数数组,
		计算你不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
		
		示例 1:
		输入:[1,2,3,1]
		输出:4
		解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
		偷窃到的最高金额 = 1 + 3 = 4 。。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/house-robber

我一个a接w接a接外圈刮给他把最大价值全部拿走

说正经的,执行我们的三步走战略:
为了简单理解,我们也可以想象为我们从第一个房子偷到最后一个房子

1.对最终情况进行解析

首先我们读题研究哈,“如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。” 表明我们在这道题中肯定不能无脑拿走所有屋子的价值
换句话说我们只可以隔一个屋子拿一个屋子的价值,这是这道题出现的限制条件

我们再来分析这个题他的最终情况:最后一间房屋我要不要偷?

我们假设最后一间屋子为J。
判断最后一间房屋要不要偷由那些情况构成呢?和条件结合来看,我们可以得出由偷 屋子J-2 并且可以偷 屋子J(情况1),或者只偷 屋子J-1而放弃偷 屋子J 和 屋子J-2(情况2)构成.

两种情况熟优熟劣?我们可以通过比较大小来判断。

Max=max(a+nums[i],b);

2.向前推导,直到推导到第一步

我们向前,向前想,一直想到最前面的情况,回到梦开始的起点,第一间屋子和第二间屋子。在这里我们来考虑我们这个 由情况构成后面的逻辑如何在开始被套用


3.研究明白第一或者前几个已知的情况如何构成后面的情况。

我们偷东西的顺序是沿着前向后偷的
动态规划的精髓就在于,每走一步的结果都是在这一步的最优解决方案

我们回到第一间屋子和第二间屋子,脑海中思考着我们在第一步总结出的逻辑思路:

第一间屋子和第二间屋子如何影响程序选择后面的屋子?
换句话说,我该如何在第三间屋子的角度来看这个问题?

我们来分类讨论一下:

  1. 我选择偷第一间屋子(情况1):
    这就意味着我还可以偷第三间屋子
    而偷了第一间和第三间屋子的我只要偷的总额比偷第二间屋子多
    就代表站在偷到第三个屋子的我偷了第一间和第三间屋子就是赚的。

  2. 我选择偷第二间屋子(情况2):
    这意味着我只偷了第二间屋子,如果我偷的总额超过第一间加第三间
    就代表站在偷到第三个屋子的我只偷第二个屋子就是赚的。

情况一和二之间可以通过比大小来判断哪种好,我们选取好的作为在该情况下的最优解。
换句话说就是我们偷到第三间屋子时我们的最优解

我们理出了我们之前得出的逻辑,即【J】、【J-1】、【J-2】之间的决定方式,并且他现在很清楚的在前三间房子中展示给了我们。
这就意味着我们可以向后面偷的每一步都用这个方法考虑了


那么现在我们用我们得到的逻辑来推导吧

我们用一个数字(int) a来记录偷到第一个屋子的最优值

`int a=nums[0];`

我们再用一个数字(int) b来记录偷到第二间屋子的最优值,这个值为第一第二间屋子中价值较大的那一间

`int b=max(nums[0],nums[1])`

然后我们来写向后推导的过程

for(int i=2;i<nums.size();i++){
    Max=max(a+nums[i],b);
    a=b;
    b=Max;
}

对于每一步向后推导来说,他都需要【J-2】和【J-1】来判断是否偷【J】
那么依据刚才我们写的a,b来说,a扮演的是【J-2】,b扮演的是【J-1】。
我们的每一步向后推导先用max函数决定出当前这一步在“情况一”与“情况二”中选出最优解并赋值给Max,
然后将【J-1】的值交给a,将【J】情况下的解,也就是【J】的值交给b。

这样操作之后,对于下一个情况【J+1】来说,a会继续扮演“【J-2】”的位置,b也会继续扮演“【J-1】”的位置,从而开始对【J+1】的推导。对于之后的“每个屋子”我们都可以用这样的逻辑进行推算。

然后我们再加上对奇奇怪怪情况的回应,就可以得到一个解答了:

if(nums.size()==1) return nums[0];
if(nums.size()==2) return max(nums[0],nums[1]);
int a=nums[0],b=max(nums[0],nums[1]),Max=nums[0];
for(int i=2;i<nums.size();i++){
    Max=max(a+nums[i],b);
    a=b;
    b=Max;
}
return Max;

总结

本人还只是一个小学生,才疏学浅,还希望大家能多多包涵,有什么不足请大家指正。
如果这篇文章帮到你请帮忙点个赞让我看到,谢谢大家抬爱。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值