leetcode 198. House Robber 动态规划 python3

一.问题描述

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.

Example 2:

Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.

二.解题思路

这道题很明显是需要用动态规划来解的,因为没有后效性。

就是说,考虑nums[i]的出现,并不会影响nums[0~i-2]子问题的最优解。当然一般来说是不影响nums[0~i-1],不过这道题要求稍微紧一点,不过也不妨碍我们用动态规划来解决问题。

动态规划来说主要就是审题审题!找到解的分割和更新方法。

分割来说,很明显如上所说,因为nums[i]的出现并不影响nums[0~i-2]的解。所以应该考虑0~i 和 0~i-2之间的关系。

可以有两种动态规划的理解思路:

1.假设dp[i]是最后选了nums[i](即以nums[i]结尾)的所有可行解中的最优解,那么对与dp[i+1]来说,它的更新为:

dp[i+1]=max(nums[i+1]+dp[i-1],nums[i+1]+dp[i-2])

对于dp[i+1]]的来说,因为选了nums[i+1],所以所有以nums[i+1]为结尾的中,倒数第二个数只可能是nums[i-1]和nums[i-2]。因此应该判断dp[i-1]和dp[i-2]哪个大然后相加。没必要去和dp[i-3]等等去比,因为dp[i-1]肯定比dp[i-3]大。

2.第一种方法比较稍微好理解一点,第二种就晦涩一点。

假设dp[i]是nums[0~i]的最优解(注意,这里最优解的结尾可能是nums[i]也可能是num[i-1],并没有固定)

此时,对于dp[i+1]来说,它的更新是,首先,虽然不知道它是以nums[i]还是nums[i-1]结尾,那么我们不如假设,

假设是以nums[i-1]结尾,那么dp[i+1]=nums[i+1]+dp[i-1]

假设是以nums[i]结尾,那dp[i+1]=dp[i],因为nums[i+1]不能和nums[i]一起出现。

综上:时间复杂度O(N),空间复杂度O(N)

更多leetcode算法题解法: 专栏 leetcode算法从零到结束

三.源码

方法1:

class Solution:
    def rob(self, nums: List[int]) -> int:
        n=len(nums)
        if n==0:return 0
        if n==1:return nums[0]
        if n==2:return max(nums)
        dp=[0]*n
        dp[0],dp[1]=nums[0],nums[1]
        for i in range(2,n):
            dp[i]=max(nums[i]+dp[i-2],nums[i]+dp[i-3])
        return max(dp[n-1],dp[n-2])

方法2:来自leetcode demo

class Solution:
    def rob(self, nums: List[int]) -> int:
        dp = [None] * len(nums)
        if not nums:
            return 0
        
        if len(nums) == 1:
            return nums[0]
        else:
            dp[0] = nums[0]
            
        if len(nums) == 2:
            return max(nums[0], nums[1])
        else:
            dp[1] = max(nums[0], nums[1])
            
        for i in range(2, len(nums)):
            take = dp[i-2] + nums[i]
            not_take = dp[i-1]
            dp[i] = max(take, not_take) 
        
        return dp[len(nums) - 1]

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值