学习目标:
每日一题:打家劫舍学习内容:
是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额
解法:
小偷可以选择偷和不偷,如果前一个偷了,那么下一个肯定是不能偷的,因为相邻的房屋在同一晚上被小偷闯入,系统会自动报警。如果上一个没偷,那么下一个可以选择偷也可以选择不偷,视情况而定。
这里可以定义一个二维数组dp[length][2],其中dp[i][0]表示第i+1(因为数组下标是从0开始的,所以这里是i+1)家偷了的最大总金额,dp[i][1]表示的是第i+1家没偷的最大总金额。那么我们找出递推公式
1,dp[i][0]=max(dp[i-1][0],dp[i-1][1])他表示如果第i+1家没偷,那么第i家有没有偷都是可以的,我们取最大值即可。
2,dp[i][1]=dp[i-1][0]+nums[i]他表示的是如果第i+1家偷了,那么第i家必须没偷,这里nums[i]表示的是第i+1家偷的金额。
递推公式找出来之后我们再来看下边界条件,第一家可以选择偷,也可以选择不偷,所以 dp[0][0]=0,第一家没偷
dp[0][1]=nums[0],第一家偷了
上面定义了一个二维数组,但每次计算的时候都只是用二维数组的前一对值,在往前面的就永远使用不到了,这样就会造成巨大的空间浪费,所以我们可以定义两个变量来解决,来看下代码
改良后代码
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
d1 = 0 #第一家没有进行偷窃
d2 = nums[0] #第一家进行了偷窃
for i in range(1,len(nums),1):
#防止dp0被修改之后对下面运算造成影响,这里
#使用一个临时变量temp先把结果存起来,计算完
#之后再赋值给dp0.
temp = max(d1,d2)
d2 = d1+nums[i]
d1 = temp
return max(d1,d2)