Leetcode 打家劫舍

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

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

示例 1:

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

示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

思路:从最后一家开始, 分两种情况:

          1. 抢最后一家, 那么第n-1 家就不能抢,否则会报警,此时只剩前n-2家可抢

          2. 最后一家不抢, 那么剩下前面n-1家可抢

          求出两种情况的最大值,依次向前递归。

 

解法 1:这是一个动态规划的题目,自然想到用递归来做,但是在最后提交解答的时候报错说超出时间限制, 仔细一想,这里面存在大量的重复计算,比如rob(nums[:n-2])会被重复计算两次。

class Solution:
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        length = len(nums)
        
        if length == 0: #递归出口
            return 0
        elif length == 1:  #递归出口
            return nums[0]
        # 从最后一家开始, 若抢最后一家,则剩下前n-2家可抢, 若最后一家不抢, 则剩下前n-1家可抢,                     
        else:
            return max(nums[length-1]+self.rob(nums[:length-2]), self.rob(nums[:length-1]))     

 

解法 2:空间换时间,用一个数组将rob(nums[:k])结果保存起来, 避免重复计算。

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        #空列表
        if n < 1:
            return 0
        
        # rob_array[k]表示前k家最多能打劫多少钱
        rob_array = [None] * (n+1)
        rob_array[:2] = [0, nums[0]]
        
        # 从前2家开始计算
        for k in range(2, n+1):
            rob_array[k] = max(nums[k-1] + rob_array[k-2], rob_array[k-1])
        
        return rob_array[n]

 

解法 3: 第二种解法的改进,更小的空间复杂度

class Solution:
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        pre, prepre, cur = 0, 0, 0
        
        for i in range(len(nums)):
            cur = max(nums[i] + prepre, pre)
            prepre = pre
            pre = cur
        
        return cur

 

你可能感兴趣的:(LeetCode)