Leetcode刷题(11) 打家劫舍系列问题

Leetcode刷题(11) 打家劫舍系列问题

方法参考labuladong的实现团灭 LeetCode 打家劫舍问题,并自己用python重写了一遍

198. 打家劫舍

方法一: 递归+备忘录

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        
        # 有多少户人家
        nums_len = len(nums)
        if nums_len == 0:
            return 0 

        # 备忘录
        mome = [-1] * nums_len
        
        # dp[start]表示由start--->end(nums_len) 能最多打劫到多少
        # 注意: start的遍历是倒着来的
        def dp(start):
            if start >= nums_len:
                return 0

            # 发现备忘录里面不是初始值的说明已经计算过了, 直接返回
            elif mome[start] != -1:
                return mome[start]
            else:
                mome[start] = max(dp(start + 1), nums[start] + dp(start + 2))
                return mome[start]
        # 最终要得到的是start = 0
        return dp(0)

用end自顶向下的递归,要处理的临界比较繁琐了,我就没有写代码

方法二: 动态规划

start是递减的(反着来的), 需要处理的临界情况比较少

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        len_nums = len(nums)
        if len_nums == 0:
            return 0
        # n+1和n+2是空屋子,假想的
        dp = [0] * (len_nums + 2)
       
        for i in range(len_nums-1, -1, -1):
            dp[i] =  max(dp[i+1], dp[i+2] + nums[i])
        return dp[0]

下面的递归方法的end是递增的(顺着来的),比较好理解但是要处理的临界情况比较繁琐

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        len_nums = len(nums)
        if len_nums == 0:
            return 0

        # 这里是用0初始化,
        dp = [0] * len_nums
        
        # 这个代码的start是顺着来的, 要处理的临界情况比较繁琐
        if len_nums >= 1:
            dp[0] = nums[0]
        if len_nums >= 2:
            dp[1] = max(nums[1], nums[0])
        

        for i in range(2, len_nums):
            dp[i] =  max(dp[i-1], dp[i-2] + nums[i])
        return dp[-1]

213. 打家劫舍 II

将nums划分为两段,然后取最大的那段即可

方法: 动态规划(状态压缩)

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        len_nums = len(nums)
        if len_nums == 0:
            return 0
        if len_nums == 1:
            return nums[0]

        start1 = -1
        end1 = len_nums - 2

        start2 = 0
        end2 = len_nums - 1

        def robRange(start, end):
            # 第一次迭代的时候,这个是后里两个空屋子
            dp_i_1 = 0  
            dp_i_2 = 0

            dp_i = 0
            for i in range(end, start, -1):
                dp_i = max(dp_i_1, nums[i] + dp_i_2)
                # 先更新dp_i_2 和 再更新dp_i_2
                dp_i_2 = dp_i_1
                dp_i_1 = dp_i
                

            return dp_i
        
        return max(robRange(start1, end1), robRange(start2, end2))

337. 打家劫舍 III

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

class Solution(object):
    def __init__(self):
        self.mome = dict()
    def rob(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 树结构的备忘录用字典来做底层结构
        
        def dp(root):
            if root == None:
                return 0 
            # 结果在备忘录内直接返回
            if root in self.mome:
                return self.mome[root]

            # 抢这家
            do_it = root.val
            if root.left != None:
                do_it += dp(root.left.left) + dp(root.left.right)
            if root.right != None:
                do_it += dp(root.right.left) + dp(root.right.right)

            # 不抢,去下家
            not_do = dp(root.left) + dp(root.right);

            self.mome[root] = max(do_it, not_do);

            return self.mome[root]
        return dp(root)
            

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值