[Leetcode刷题总结系列][Dynamic programming]198. House Robber

You are a professional robber who is planing to rob houses along a street. Each house has a certain amount of money stashed, the only constraint that stopping you from robbing each of them is that adjacent house has security system connected and it will automatically contact the police if two adjacent houses were broken into at 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. 

Dynamic Programming有两个基本原则:
1. Optimal Substructure
2. Overlapping Subproblems

那么运用在这道题目时,应当考虑到抢劫的基本原则是不能抢劫相邻的两间房子。由此得到抢劫的两种基本情况:
1. 前一间房子被抢劫了
2. 前一间房子被抢劫了
如果我们用robbedmoney[i] 来表示抢劫前i间房子的最优结果,用nums[i]来表示第i间房子中的钱数
那么robbedmoney[nums.length]就是我们想要的最终结果。
那么相应的induction应当分为如下两种情况:
1. 如果前一间房子(第(i-1)间)被抢劫了,那么抢劫前i间房子的最优抢劫结果为max{robbedmoney[i-1], robbedmoney[i-2]+nums[i]}
2. 如果前一间房子(第(i-1)间)没有被抢劫,那么抢劫前i间房子的最优抢劫结果为robbedmoney[i-2]+nums[i]
推导的base case如下:
1. 当nums.length == 0时,最优抢劫结果为0,因为没有房子。
2. 当nums.length == 1时,最优抢劫结果为nums[0],因为只有一间房子。
由此分析得出的代码如下:
该段代码的时间和空间复杂度分别为:O(n)和O(n)
public class Solution {
    public int rob(int[] nums) {
        /*
        Dynamic programming
        Bottom-up approach
        Since we cannot rob 2 adjacent houses, generally, we cannot rob house[n] and house [n-1] at the same night
        So the basic idea is to see if house[n-1] has been robbed
        If house[n-1] has been robbed, then the optimal approach should be max{robbedmoney(n-1), robbedmoney(n-2)+nums[n]}
        If house[n-1] hasn't been robbed, then the optimal approach should be robbedmoney(n-2)+nums[n]
        */
        
        int l = nums.length;
        if (l == 0){
            return 0;
        }

        int[] robbedmoney = new int[l]; //robbedmoney[i] array is used to store the maximum amount of money that can be robbed from the first i houses.
        for (int i = 0; i < l; i ++){
            if (i == 0){
                robbedmoney[i] = nums[i];
            }
            else if (i == 1){
                robbedmoney[i] = Math.max(nums[i], nums[i-1]);
            }
            else{
                robbedmoney[i] = Math.max(robbedmoney[i - 2] + nums[i], robbedmoney[i-1]);
            }
        }
        
        return robbedmoney[l - 1];
        
    }
}

实际上,在不需要重现(既Dynamic programming 中的Reconstruction)抢劫的每一步的具体选项的情况下,我们完全不需要维护O(n)大小的数组。而只需要记录前一间房子未抢劫和前一间房子已抢劫两种情况即可。这样可以将空间复杂度降到恒定值,时间复杂度仍然为O(n)。
新的代码如下:
public class Solution {
    public int rob(int[] nums) {
        /*
        As we don't need to reconstruct the solutions we have made, we don't have to keep track of an array of length l
        In construct, we only have to record the amount of money we can rob under the circumstance where:
        i) the previous house have been robbed ==> robpreviousone
        ii) the previous house have not been robbed ==> notrobpreviousone
        */
        int l = nums.length;
        if (nums == null || l == 0){
            return 0;
        }
        if (l == 1){
            return nums[0];
        }
        int robPreviousOne = 0;
        int notrobPreviousOne = 0;
        for (int i = 0; i < l; i ++){
            //if we don't rob current house, take the maximam amount of money can be robbed from not robbing and robbing previous house.
            int currentNotRobbed = Math.max(robPreviousOne, notrobPreviousOne);
            //if we rob current house, add the the amount of money that can be took form current hosue to the amount of money from not robbing previous house.
            int currentRobbed = notrobPreviousOne + nums[i];
            
            //renew the values for next iteration
            robPreviousOne = currentRobbed;
            notrobPreviousOne = currentNotRobbed;
        }
        
        //return the maximum amount of money we can rob provided we considering both of the options
        return Math.max(robPreviousOne, notrobPreviousOne);
    }
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

耀凯考前突击大师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值