打劫房屋 II

题目描述:在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

样例:给出nums = [3,6,4], 返回 6, 你不能打劫3和4所在的房间,因为它们围成一个圈,是相邻的.


这是上一道题“打劫房屋”(详见:点击打开链接)的延伸。所以如果你上一道题没搞懂,应该先去看上一题。看明白了再来做这道题。很多上一题的东西我在这里会略过不讲。

和上一题唯一的不同在于现在房屋的排列变成了一个环。因此,我们设计算法的时候也就多了一个需要考虑的因素,那就是打劫前 n 个房屋的最大收益与打劫前 n - 1个房屋取得最大收益的方案中是否打劫了第1个房屋有直接关系。我们还是用一个列表record记录结果,record[i]表示打劫前 i 个房屋的最大收益

试想,如果我们规定不能打劫第1个房屋,那么,这时就跟上一题没存在环的情况是一样的,所以我们用上一题的算法计算从第2个元素开始到最后一个元素的最大收益就行(从第2个开始是因为第1个不打劫,忽略);而如果规定必须打劫第1个房屋,那么,最后一个房屋肯定不能被打劫(有环),因此,这时候用上一题的算法计算从第1个元素开始到倒数第二个房屋构成的序列,就可以得到在打劫第1个房屋的前提下,获得的最大收益,两个值一比较,取最大值。


代码如下:

class Solution:
    # @param nums: A list of non-negative integers.
    # return: an integer
    def houseRobber2(self, nums):
        if len(nums) == 0:
            return 0
        if len(nums) == 1:
            return nums[0]
        # begin1, end1表示必须打劫第1个房屋的情况
        # begin2, end2表示不能打劫第1个房屋的情况
        begin1, begin2 = 0, 1
        end1, end2 = len(nums) - 2, len(nums) - 1

        return max(self.helper(nums, begin1, end1), self.helper(nums, begin2, end2))

    def helper(self, nums, begin, end):
        n = end - begin + 1
        if n == 0:
            return 0
        if n == 1:
            return nums[begin]
        record = [0 for i in range(n)]
        record[0] = nums[begin]
        record[1] = max(nums[begin], nums[begin + 1])
        cur = 2
        while cur < n:
            record[cur] = max(record[cur - 1], record[cur - 2] + nums[begin + cur])
            cur += 1
        return record[n - 1]
        # write your code here


我用了一个helper函数实现上一题中的算法(详见:点击打开链接),只不过加了两个参数begin和end,表示参加计算的数组的开始和结束部分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值