213. House Robber II

Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.
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.

这道题将房屋排列换成了环形排列,也就是首尾相连,所以我们必须避免第一间房和最后一间房同时被抢劫的情况。因为安全系统和House Robber并没有不同,所以我们的动态规划方程和初始化变化都不大,基本一致。 如何排除第一间房和最后一间房同时被抢的情况呢? 你可以想到直接去改变动归方程里的f[nums.length - 1],但仔细一想,这样解就必须追溯到前面前面直到第一间房,并没有能够直接删掉我们需要避免的情况的方法,所以我们转换一下思路。我们可以分两种情况来看:如果我们选了第一间房,则我们不能选最后一间房;我们没选第一间房,则我们可以选最后一间房。然后我们再在这两者之间选较大的那个。

    public int rob(int[] nums) {
        int max1 = helper(nums, 0, nums.length - 2);
        int max2 = helper(nums, 1, nums.length - 1);
        return Math.max(max1, max2);
    }
    
    private int helper(int[] nums, int i, int j){
        if (nums == null || nums.length == 0){
            return 0;
        }
        if (nums.length == 1){
            return nums[0];
        }
        if (i == j){
            return nums[i];
        }
        int[] f = new int[nums.length];
        f[i] = nums[i];
        f[i + 1] = Math.max(nums[i], nums[i + 1]);
        for (int k = i + 2; k <= j; k++){
            f[k] = Math.max(f[k - 2] + nums[k], f[k - 1]);
        }
        return f[j];
    }
}

这道题的状态方程说明f[i] 只与f[i - 1], f[i - 2]和nums[i]有关,所以我们可以用滚动数组来进行空间优化. 不过要注意,我们可以取模的必须是f[i]变成f[i % 2], 永远不能对数组元素取模,比如nums[i] 变成nums[i % 2],否则会出错。

class Solution {
    public int rob(int[] nums) {
        int max1 = helper(nums, 0, nums.length - 2);
        int max2 = helper(nums, 1, nums.length - 1);
        return Math.max(max1, max2);
    }
    
    private int helper(int[] nums, int i, int j){
        if (nums == null || nums.length == 0){
            return 0;
        }
        if (nums.length == 1){
            return nums[0];
        }
        if (i == j){
            return nums[i];
        }
        int[] f = new int[2];
        f[i % 2] = nums[i];
        f[(i + 1) % 2] = Math.max(nums[i], nums[i + 1]);
        for (int k = i + 2; k <= j; k++){
            f[k % 2] = Math.max(f[(k - 2) % 2] + nums[k], f[(k - 1) % 2]);
        }
        return f[j % 2];
    }
}

你可能感兴趣的:(213. House Robber II)