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

来源:互联网 发布:淘宝御泥坊官网 编辑:程序博客网 时间:2024/05/21 12:39
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 tonightwithout 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);    }}







0 0