LeetCde#198: House Robber

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38283262/article/details/84101995

Description

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.
Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.

Solution

解动态规划题目一般有三种递进的思路:

  1. 找到递归关系(或者说是状态转移方程)
  2. 使用递归
  3. 使用递归+备忘录
  4. 使用循环+备忘录
  5. 使用循环

再来看看这道题。如果抢劫当前房子的话,那么上一个房子就不能被抢,此时的解为上上个房子的解加上当前房子的值;如果不抢劫当前房子的话,此时的解就为上个房子的解。因此,我们可以很容易的得到状态转移方程为f(n) = Max(f(n-2) + curr, f(n-1))

递归

public class Solution {
    public int rob(int[] nums) {
        return rob(nums, nums.length-1);
    }
    
    private int rob(int[] nums, int i) {
    	if(i < 0)
    		return 0;
    	return Math.max(rob(nums, i-2)+nums[i], rob(nums, i-1));
    }
}

递归+备忘录

使用递归会产生很多重复的计算,因此可以使用一个备忘录数组来保存已计算出的结果,避免重复递归。

public class Solution2 {
	int[] memo;	
	
    public int rob(int[] nums) {
    	memo = new int[nums.length];
    	Arrays.fill(memo, -1);
        return rob(nums, nums.length-1);
    }
    
    private int rob(int[] nums, int i) {
    	if(i < 0)
    		return 0;
    	if(memo[i] >= 0)
    		return memo[i];
    	int res = Math.max(rob(nums, i-2)+nums[i], rob(nums, i-1));
    	memo[i] = res;
    	return res;
    }
}

循环+备忘录

递归操作可以使用循环替代。

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

循环

不使用备忘录,而用两个变量来保存前两个状态的解。

public class Solution4 {
    public int rob(int[] nums) {
        if(nums.length == 0) return 0;
        if(nums.length == 1) return nums[0];
        int prev1 = nums[0];
        int prev2 = Math.max(nums[1], prev1);
        for(int i = 2; i < nums.length; i++) {
        	int curr = Math.max(prev1+nums[i], prev2);
        	prev1 = prev2;
        	prev2 = curr;
        }
        return prev2;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_38283262/article/details/84101995