LeetCode192:House Robber

来源:互联网 发布:云计算运维和售前 编辑:程序博客网 时间:2024/06/11 05:06

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.

这是道动态规划的问题。假设给定的vector为[2,3,4,1,6,5]
可以这么来定义DP的状态和状态转移方程:
A[0]表示抢劫前0户(必须抢第0户)的钱为2。
A[1]表示抢劫前1户(必须抢第1户)的钱为3。因为抢了第1户,所以不能抢第0户了。
A[2]表示抢劫前2户(必须抢第2户)的钱的A[0]+4。因为抢了第2户,所以不能抢第1户。
A[3]表示抢劫前3户(必须抢第3户)的钱为max{A[0],A[1]}+1。因为抢了第3户,所以不能抢第2户,只能取A[0],A[1]中的最大值。
这样状态转移方程为:
A[i]=max{A[j],0}+data[i]。0<=j<i-1。
抢劫数目最多的的钱为:max{A[i]}。0<=i<n
基于这个状态和状态转移方程的代码如下:
runtime:0ms
class Solution {public:    int rob(vector<int>& nums) {        int length=nums.size();        int *A=new int[length];//A[i] represent the money of rob the room of i and less index.        int maxMoney=0;        for(int i=0;i<nums.size();i++)        {            A[i]=0;            for(int j=0;j<i-1;j++)            {                if(A[j]>A[i])                    A[i]=A[j];            }            A[i]+=nums[i];            if(A[i]>maxMoney)                maxMoney=A[i];        }        delete [] A;        return maxMoney;    }};

这种解法的时间复杂程度是O(N^2)。因为存在两层的for循环,但是可以发现上面代码中的第二层for循环其实可以进行一定程度的简化。因为对于我们定义的A[i]而言,A[i]代表在必须抢劫第i个房间的前提下还抢劫小于第i个索引的房间的最大值。如果我们将A[i]的含义做一点点小的更改,就可以省略掉第二层for循环了。这样时间复杂程度变成了O(N)。
依然假设给定的vector为nums=[2,3,4,1,6,5]。下面是重新定义的状态:
B[0]表示加入第0户时抢劫的最大数目为2.
B[1]表示接着加入第1户时抢劫的最大数目为3.即max{2,3}。
B[2]表示接着加入第2户时抢劫的最大数目为6,即max{B[0]+4,B[1]}
B[3]表示接着加入第3户时抢劫的最大数目为6,即max{B[1]+1,B[2]}
...
现在由于B[i]的含义发生了变化,它代表多加一户时能抢劫的最多的钱。所以状态转移方程也变化为:
B[i]=max{B[i-2]+nums[i],B[i-1]}.2<=i<n
B[0]=nums[0],B[1]=max{nums[0],nums[1]}
最终要求解的结果是B[n-1]。时间复杂度为O(N)。
runtime:0ms
class Solution {public:    int rob(vector<int>& nums) {        int length=nums.size();        if(length==0)            return 0;        if(length==1)            return nums[0];        if(length==2)            return max(nums[0],nums[1]);                    int *B=new int[length]();        B[0]=nums[0];        B[1]=max(nums[0],nums[1]);        for(int i=2;i<length;i++)        {            B[i]=max(B[i-2]+nums[i],B[i-1]);        }        return B[length-1];    }};

从上面两种解法中可以发现定义好了初始状态和状态转移方程之后代码就很好编写了。而且同一个问题对状态的不同定义也会导致不同的时间复杂程度。

可以发现如果题目对于连续性有要求可以使用第一种思想,如果没有要求可以使用第二种思想。
0 0