LeetCode-198. 打家劫舍

题目描述:你是一个专业的强盗,计划抢劫沿街的房屋。每间房都藏有一定的现金,阻止你抢劫他们的唯一的制约因素就是相邻的房屋有保安系统连接,如果两间相邻的房屋在同一晚上被闯入,它会自动联系警方。

给定一个代表每个房屋的金额的非负整数列表,确定你可以在没有提醒警方的情况下抢劫的最高金额。

  1. 暴力搜索方法
    思路:文中给出不能连续抢两家,因此假设从最后一个房屋开始抢,最后一个房屋为index。将原问题分割成子问题,子问题的最优决策可以导出原问题的最优决策。现有两种可能情况,当前房屋抢和当前房屋不抢。若当前房屋抢,则下一房屋不能抢;若当前房屋不抢,则下一房屋可抢;选出这两种情况的最大值,递归执行,直到index<0。
    public int solve(int index, int[] nums){
        if(index < 0){
            return 0;
        }
        int max = Math.max(nums[index] + solve(index - 2, nums), solve(index - 1, nums));
        return max;
    }
    
    public int rob(int[] nums) {
        return solve(nums.length-1, nums);
    }

这里写图片描述
此种暴力方法在执行第56个测试用例时,超出时间限制。
假设我们抢n-1家,那么接下来的执行方案:
n-1 ->(n-3, n-4, n-5)
假设我们抢n-2家,那么接下来的方案为:
n-2 ->(n-4, n-5)
那么我的两种决策方式只是影响能不能抢n-3,在n-3之后都是随便抢的;通过观察上述两种方案,我们发现了n-4,n-5被重复计算。因此,每一家都有两种可能可能,抢或者不抢。则该算法的时间复杂度为: O ( 2 n ) O(2^n) O(2n)
为了避免上述的重复计算,我们初始化一个数组来记录所有记录为-1,如果当前index被算过,就记录下来。因此,每次判断该屋抢还是不抢后,都会得到一个index值。这就是去冗余,用采用空间换时间的方法。因此当n-1房屋的最优解算过后,就能推导出n房屋的最优解。这就是动态规划的思想。
因此,我们考虑使用动态规划,设置result[]数组记录抢夺该房屋可能的最大收益。
自顶向下解法

class Solution {
    public static int[] result;
    
    public int solve(int index, int[] nums){
        if(index < 0){
            return 0;
        }
        
        if(result[index] >= 0){
            return result[index];
        }
        
        result[index] = Math.max(nums[index] + solve(index-2 , nums), solve(index-1, nums));
        return result[index];
    }
    
    public int rob(int[] nums) {
        result = new int[nums.length];
        for(int i=0; i < result.length; i++){
            result[i]=-1;
        }
        return solve(nums.length-1, nums);
    }
}

对于每个房屋我们都算了一次,那么时间复杂度为 O ( n ) O(n) O(n)
自底向上解法

	public int rob(int[] nums) {
        if (nums.length == 0){
            return 0;
        }
        
        if (nums.length == 1){
            return nums[0];
        }
        
        if (nums.length == 2){
            return Math.max(nums[0], nums[1]);
        }
        
        int[] result = new int[nums.length];   
        result[0] = nums[0];
        result[1] = Math.max(nums[0], nums[1]);
        
        for(int index=2; index < result.length; index++){
            result[index] = Math.max(nums[index] + result[index-2], result[index -1]);
        }
        
        return result[nums.length -1];
    }
}

自底向上,编码简单,递推(自顶向下为递归)。既然自底向上不需要递归,那么就不需要solve函数了。我们只要处理好边界条件,然后计算即可。
2. python解法

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

你可能感兴趣的:(LeetCode)