打家劫舍(动态规划)

打家劫舍(Ⅰ)
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

考虑所有可能的抢劫方案过于困难。一个自然而然的想法是首先从最简单的情况开始。记:

f(k) = 从前 k 个房屋中能抢劫到的最大数额,A_iA i = 第 i 个房屋的钱数。

首先看 n = 1 的情况,显然 f(1) = A_1A 1 。

再看 n = 2,f(2) = max(A_1A 1 , A_2A 2 )。

对于 n = 3,有两个选项:

抢第三个房子,将数额与第一个房子相加。

不抢第三个房子,保持现有最大数额。

显然,你想选择数额更大的选项。于是,可以总结出公式:

f(k) = max(f(k – 2) + A_kA k , f(k – 1))

我们选择 f(–1) = f(0) = 0 为初始情况,这将极大地简化代码。

答案为 f(n)。可以用一个数组来存储并计算结果。不过由于每一步你只需要前两个最大值,两个变量就足够用了。

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 0:
            return 0
        pre = cur = 0
        for c in nums:
            pre, cur = cur, max(pre + c, cur)
        return cur

打家劫舍(Ⅱ)
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题约化为两个单排排列房间子问题:
在不偷窃第一个房子的情况下(即 nums[1:]nums[1:]),最大金额是 p_1p1;在不偷窃最后一个房子的情况下(即 nums[:n-1]nums[:n−1]),最大金额是 p_2p 2 。综合偷窃最大金额: 为以上两种情况的较大值,即 max(p1,p2)max(p1,p2) 。

class Solution:
    def rob(self, nums: [int]) -> int:
        def my_rob(nums):
            cur, pre = 0, 0
            for num in nums:
                cur, pre = max(pre + num, cur), cur
            return cur
        return max(my_rob(nums[:-1]),my_rob(nums[1:])) if len(nums) != 1 else nums[0]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值