213.打家劫舍II

题目

'''
Description: 213.打家劫舍II
Autor: 365JHWZGo
Date: 2021-12-06 10:26:03
LastEditors: 365JHWZGo
LastEditTime: 2021-12-06 14:33:15
'''

思路

这道题和昨天的打家劫舍最根本步骤一致,但最重要的步骤就是知道最后一个房子和第一个房子是否被盗取!

分为的类型有:
第一个房子被盗取,最后一个房子没有被盗取【YES】
第一个房子被盗取,最后一个房子被盗取【NO】
第一个房子没有被盗取,最后一个房子被盗取【YES】
第一个房子没有被盗取,最后一个房子没有被盗取【YES】
由此我们可以知道只要最后一个和第一个房子没有同时被盗,那么我们就还可以使用昨天的结论。

那么问题来了,怎样才能知道呢?
方法一:
使用标记,意思是在得到当前看来最多的金钱数时,是由哪些被盗的房子的组成的,最后再判断第一个房子和最后一个房子是否同时被盗取。

方法二:【解释下面这段代码】
正向遍历和反向遍历,观察结果倒数两个是否一致
1.正向一致代表:说明最后一个房子没有被盗
2.反向一致代表:说明第一个房子没有被盗
而我们只要说明1和2有一个成立就能证明可以使用198.打家劫舍的结论做题,当两个都不成立时,说明第一个房子和最后一个房子都被盗取了,此时会出发警报,为了避免这种情况出现,我们需要舍去一个房子的金钱数,要么舍去第一个房子,要么舍弃最后一个房子

if dp[-2]==dp[-1] or dp1[-1]==dp1[-2]:
    return dp[-1]
else:
    return max(dp[-2],dp1[-2])

此时可能又有心急的小伙伴问了,假如是【1,3,2】时,抛弃的不是第一个房子或最后一个房子呀!

别急,你细想,这是一个环,其实实质上来说并没有哪个房子是第一个,哪一个房子是最后一个!!max(dp[-2],dp1[-2])其实是抽象的来说抛弃了第一个或最后一个,可并没有说只放弃了最后一个或第一个。所以切记不能写成dp[-1]-min(nums[0],nums[-1])。

直观解题思路:
            它和昨天的打家劫舍不同的是在于最后一个房子的处理
            昨天的是一条线,最后一个房子没有邻居
            而今天的是一个环,最后一个房子能否盗取取决于第一个房子是否盗取以及前一个房子是否盗取
思路:
        1.确定dp数组以及下标含义
            dp[i]表示在盗取第i家金钱后的最大金钱数
        2.确定递推公式
            dp[i]=max(dp[i-2]+nums[i],dp[i-1])
        3.初始化dp数组
            dp[0]=nums[0]
            dp[1]=max(nums[0],nums[1])
        4.确定遍历顺序
            从小到大依次遍历
        5.举例推导
            nums=[1,2,3,4]
            nums.reverse()-> [4, 3, 2, 1]
            正序:[1, 2, 4, 6]
            倒序:[4, 4, 6, 6]
            6

代码

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 1:
            return nums[0]
        dp = [0] * len(nums)        
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for i in range(2, len(nums)):
            dp[i] = max(dp[i-2]+nums[i], dp[i-1])
            
        nums.reverse()
        dp1 = [0] * len(nums)
        dp1[0] = nums[0]
        dp1[1] = max(nums[0], nums[1])
        for i in range(2, len(nums)):
            dp1[i] = max(dp1[i-2]+nums[i], dp1[i-1])
        if dp[-2]==dp[-1] or dp1[-1]==dp1[-2]:
            return dp[-1]
        else:
            return max(dp[-2],dp1[-2])

运行结果

在这里插入图片描述

代码2(精简版)

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 1:
            return nums[0]
        dp = [0] * len(nums)    
        dp1 = dp+[]    
        nums1 =nums+[]
        nums1.reverse()
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        dp1[0] = nums1[0]
        dp1[1] = max(nums1[0], nums1[1])
        for i in range(2, len(nums)):
            dp[i] = max(dp[i-2]+nums[i], dp[i-1])
            dp1[i] = max(dp1[i-2]+nums1[i], dp1[i-1])
        
        if dp[-2]==dp[-1] or dp1[-1]==dp1[-2]:
            return dp[-1]
        else:
            return max(dp[-2],dp1[-2])

运行结果2

在这里插入图片描述

总结

前面写的已经很清楚了,总结就表扬一下自己吧!
题还是有一定难度的!望自己加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

365JHWZGo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值