Python版-LeetCode 学习:打家劫舍(, II,III)

198. 打家劫舍

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

示例 1:   输入:[1,2,3,1]   输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
           偷窃到的最高金额 = 1 + 3 = 4 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber

方法1:动态规划

class Solution:
    def rob(self, nums: List[int]) -> int:
        n=len(nums)
        dp=[0 for i in range(n+2)]
        # n-1 是为了让i和nums对其
        for i in range(n-1,-1,-1):
            # 两种状态比对,不抢:当前所获等于上一次的获得;抢:当前所获等于当前房屋(nums[i])加上上次所获
            dp[i]=max(dp[i+1],nums[i]+dp[i+2])
        
        return dp[0]

方法2:递归

class Solution:
    def rob(self, nums: List[int]) -> int:
        global memo
        memo=[-1 for i in range(len(nums))]
        # 自顶向上
        return self.dp(nums,0)
    
    def dp(self,nums: List[int],start: int)-> int:
        if start>=len(nums):
            return 0
        if memo[start]!=-1: return memo[start]
        rst =max(
            # 不抢,去下家
            self.dp(nums,start+1),
            # 抢,让后去下下家
            nums[start]+ self.dp(nums,start+2)
            )
        memo[start]=rst

        return rst

 

 213. 打家劫舍 II

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:    输入: [2,3,2]     输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber-ii

方法1:动态规划

class Solution:
    def rob(self, nums: List[int]) -> int:
        n=len(nums)
        if n==0 : return 0
        if n==1: return nums[0]

        return max(self.robPlan(nums,0,n-2),self.robPlan(nums,1,n-1))
    
    def robPlan(self,nums:List[int],start:int,end:int)-> int:
        # 初始化
        state_0,state_1=0,0
        rst=0
        for i in range(end,start-1,-1):
            # 不抢or抢,state_0:上次没抢后的金额,state_1:上次抢过后的金额
            # rst:这次抢与不抢的比较的结果
            rst=max(state_0,state_1+nums[i])
            # 这次不抢,就作为下次抢的获利基数
            state_1=state_0
            # 这次抢的结果,就作为下次不抢的获利数
            state_0=rst

        return rst

参考:https://leetcode-cn.com/problems/house-robber-ii/solution/213-da-jia-jie-she-iidong-tai-gui-hua-jie-gou-hua-/

337. 打家劫舍 III

 在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:输入: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

输出: 7 
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber-iii
方法1:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def __init__(self):
        self.memo=collections.defaultdict(int)

    def rob(self, root: TreeNode) -> int:
        if root == None: return 0

        if root in self.memo:
            return self.memo[root]
        # 抢,就查找当前值以及下下家(孙节点)的值,并求和
        do_it=root.val \
        +(0 if root.left==None else self.rob(root.left.left)+self.rob(root.left.right))\
        +(0 if root.right==None else self.rob(root.right.left)+self.rob(root.right.right))
        # 不抢,不抢当前值就抢下家(儿子节点)的值,并求和
        not_do=self.rob(root.left)+self.rob(root.right)
        # 取最大值
        rst=max(do_it,not_do)

        self.memo[root]=rst
        return rst

 

你可能感兴趣的:(LeetCode算法)