LeetCode 198 House Robber

题目

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 1:

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.

Example 2:

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.


动态规划

状态
  • 递归函数的定义就是动态规划中的状态;
  • 本问题的状态:考虑偷取 [x ... n - 1] 范围里的房子;
状态转移
  • 根据状态的定义,决定状态的转移;
  • 状态转移方程式:f(0) = max { v(0) + f(2), v(1) + f(3), v(2) + f(4), ... , v(n-3) + f(n-1), v(n-2), v(n-1)
  • 对于每一个动态规划问题,都要从状态和状态转移的角度思考;

解法思路(一)

思路描述
  • 在一个数组上,取元素,取的元素不能相邻,要取到的元素之和最大的那个解;
  • 首先要找出所有的取法;
所有的取法
  • 如果第一次取第 0 个元素,那么第二次只能从第 2 个元素开始取;
  • 如果第一次取第 1 个元素,那么第二次只能从第 3 个元素开始取;
  • ...
  • 根据以上规律,画出数组长度为 5 的抢劫递归树,如下:
LeetCode 198 House Robber_第1张图片
算法过程.png
  • 求上图到叶子节点所有路径之和最大的路径,把这条路径的和返回;
动态规划的基础
  • 图中用相同颜色标出的子问题是相同的;
  • 由于出现了相同子问题,就可以用记忆化递归;
  • 通过观察记忆化递归的代码,发现用于记忆的数组的变化规律,从这个规律入手,写出动态规划的代码;

解法实现(一)递归

实现细节
  • 参照递归树,阅读代码;
package leetcode._198;

public class Solution198_1 {

    public int rob(int[] nums) {
        return rob(nums, 0);
    }

    private int rob(int[] nums, int index) {

        if (index >= nums.length) {
            return 0;
        }

        int res = 0;
        for (int i = index; i < nums.length; i++) {
            res = Math.max(res, nums[i] + rob(nums, i + 2));
        }

        return res;
    }

    public static void main(String[] args) {

        int[] nums = {2, 7, 9, 3, 1};
        Solution198_1 s = new Solution198_1();
        int res = s.rob(nums);
        System.out.println(res);

    }

}

解法实现(二)记忆化递归

实现细节
  • 参照递归树,阅读代码;
package leetcode._198;

import java.util.Arrays;

public class Solution198_2 {

    private int[] memo;

    public int rob(int[] nums) {

        memo = new int[nums.length];
        Arrays.fill(memo, -1);

        return rob(nums, 0);
    }

    private int rob(int[] nums, int index) {

        if (index >= nums.length) {
            return 0;
        }

        if (memo[index] != -1) {
            return memo[index];
        }

        int res = 0;
        for (int i = index; i < nums.length; i++) {
            res = Math.max(res, nums[i] + rob(nums, i + 2));
        }
        memo[index] = res;

        return res;
    }

    public static void main(String[] args) {

        int[] nums = {2, 7, 9, 3, 1};
        Solution198_1 s = new Solution198_1();
        int res = s.rob(nums);
        System.out.println(res);

    }

}

解法实现(三)动态规划

实现细节
  • 参照记忆化递归的代码,观察数组 memo 的变化规律,观察以下动态规划的代码;
package leetcode._198;

public class Solution198_3 {

    private int[] memo;

    public int rob(int[] nums) {

        int n = nums.length;
        memo = new int[n];

        if (n <= 0) {
            return 0;
        }

        memo[n - 1] = nums[n - 1];

        int res = 0;
        for (int i = n - 2; i >= 0; i--) {
            for (int j = i; j < n; j++) {
                memo[i] = Math.max(memo[i], j + 2 < n ? nums[j] + memo[j + 2] : nums[j]);
            }
        }

        return memo[0];
    }

    public static void main(String[] args) {

        int[] nums = {2, 7, 9, 3, 1};
        Solution198_3 s = new Solution198_3();
        int res = s.rob(nums);
        System.out.println(res);

    }

}

返回 LeetCode [Java] 目录

你可能感兴趣的:(LeetCode 198 House Robber)