198. / 213. House Robber(I / II)

198. House Robber

My Submissions
Question
Total Accepted: 49421  Total Submissions: 151667  Difficulty: Easy

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.

Credits:
Special thanks to @ifanchu for adding this problem and creating all test cases. Also thanks to @ts for adding additional test cases.

Subscribe to see which companies asked this question

Hide Tags
  Dynamic Programming
Hide Similar Problems
  (M) Maximum Product Subarray (M) House Robber II (M) Paint House (E) Paint Fence

分析:

首先理清思路:
最值方案问题,考虑采用动态规划
定义子问题:令maxV[i]表示盗贼从第1家到达第i家能偷到的最大money数;

显然对于每一栋房子,只能做两种选择----偷或者不偷,

1),如果不偷,显然,还是上一次的最大利润数maxV[i-1]

2),如果偷,那么nums[i]的利润已经获得。但是这里因为第i-1次存在不偷或者偷的情况,所以又分两种情况

A),如果i-1次不偷,显然maxV[i-1]=maxV[i-2],可知maxV[i]=maxV[i-2]+nums[i]

B),如果i-1次偷,显然为了能产生maxV[i]的最大值就不能来自子问题maxV[i-1],即maxV[i-2]是安全的最大值来源,可知即使偷,答案还是maxV[i]=maxV[i-2]+nums[i]
所以当到达第i家的时候,i>=2,此时能够得到的钱数应该为maxV[i]=max{maxV[i-1],maxV[i-2]+nums[i]},

时间复杂度O(N),空间复杂度O(N)

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() == 0)
             return 0;
        vector<int> maxV(nums.size());
        maxV[0] = nums[0];
        maxV[1] = max(nums[0], nums[1]);
        for(int i = 2; i < nums.size(); i ++)
            maxV[i] = max(maxV[i-2]+nums[i], maxV[i-1]);
        return maxV[nums.size()-1];
    }
};


学习讨论区的优化,另一种形式:

实际上我们并不需要申请一个数组来获取答案,从上面的看得出,我们只需要前一次偷获取的最大利润,和前一次未偷获取的最大利润即可。
Since we are not allowed to rob two adjacent houses, we keep two variables pre and cur. During the i-th loop, pre records the maximum profit that we do not rob the i - 1-th house and thus the current house (the i-th house) can be robbed while cur records the profit that we have robbed the i - 1-th house.
The code is as follows.

空间复杂度降为1,时间复杂度还是一样的:

class Solution {
public: 
    int rob(vector<int>& nums) {
        int  pre = 0, cur = 0;
        for (int i = 0; i < nums.size(); i++) {
            int temp = max(pre + nums[i], cur);
            pre = cur;//没有偷i-1栋房子的最大利润
            cur = temp;//偷了i-1栋房子的最大利润
        }
        return cur;
    }
};




213. House Robber II

My Submissions
Question
Total Accepted: 20380  Total Submissions: 69651  Difficulty: Medium

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.

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.

Subscribe to see which companies asked this question

Hide Tags
  Dynamic Programming
Show Similar Problems


没思路,没理解题意:不理解这个数组怎么体现循环呢?
别人的算法(参考讨论区)
因为第一个和最后一个不能同时偷
创建两个独立的数组,其中一个包括第一个不包括最后一个,另一个包括最后一个但不包括第一个
分别利用House Robber的算法,两者的较大值就是最优值

class Solution {
public:
    int robOriginal(vector<int>& nums) {
        if(nums.size() == 0)
             return 0;
        vector<int> maxV(nums.size());
        maxV[0] = nums[0];
        maxV[1] = max(nums[0], nums[1]);
        for(int i = 2; i < nums.size(); i ++)
            maxV[i] = max(maxV[i-2]+nums[i], maxV[i-1]);
        return maxV[nums.size()-1];
    }
    
    int rob(vector<int>& nums) {
        if(nums.empty()) 
            return 0;
        if(nums.size() == 1) 
            return nums[0];

        vector<int> numsA(nums.begin() + 1, nums.end());
        vector<int> numsB(nums.begin(), nums.end()-1);

        return max(robOriginal(numsA), robOriginal(numsB));
    }
};



九度女生排座位

本题连动九度女生排座位问题,上面的问题也可以考虑下面的形式来解:

题目描述:

计算机学院的男生和女生共n个人要坐成一排玩游戏,因为计算机的女生都非常害羞,男生又很主动,所以活动的组织者要求在任何时候,一个女生的左边或者右边至少有一个女生,即每个女生均不会只与男生相邻。现在活动的组织者想知道,共有多少种可选的座位方案。


例如当n为4时,共有
女女女女, 女女女男, 男女女女, 女女男男, 男女女男, 男男女女, 男男男男
7种。

输入:

输入包含多组测试用例,每组测试用例仅包含一个整数n(1<=n<=1000)。

输出:

对于每组测试用例,输出一个数代表可选的方案数,为防止答案过大,答案对1000000007取模。

样例输入:
1
2
4
样例输出:
1
2
7
#include "vector"  
#include "string"  
#include "algorithm"  
#include <iostream>  
#include "stack"  
#include <cmath>  
#include <set>  
  
using namespace std;  
  
//最值方案问题,考虑采用动态规划  
//令dp[i][0]表示共i个人的座位方式,且最后一个是男生,dp[i][1]则是女生  
//无论什么时候最后一个人要么是男要么是女  
//如果最后一个是男生,显然dp[i][0] = dp[i - 1][0] + dp[i - 1][1];  
//因为前面的女生已经满足座位关系,再加一个男生一样满足座位关系  
//如果最后一个是女生,显然它的前一个不能是男生,那么只能是女生,  
//此时方式数目就是dp[i-1][1]  
//但是dp[i-1][1]中并没包括倒数第二女生前面可以是男生的情况(因为最后一个也是女生,所以此时是可以的),此时数目是dp[i-2][0]  
const int maxx = 1001;  
const int MOD = 1000000007;  
long  dp[maxx][2];  
void init()  
{  
    long sum = 0;  
  
    dp[1][0] = 1;//男生  
    dp[1][1] = 0;//女生  
  
    dp[2][0] = 1;//男生  
    dp[2][1] = 1;//女生  
    for (int i = 3; i<1001; ++i)  
    {  
        //男生  
        dp[i][0] = dp[i - 1][0] + dp[i - 1][1];  
        dp[i][0] %= MOD;  
        //女生  
        dp[i][1] = dp[i - 2][0] + dp[i - 1][1];  
        dp[i][1] %= MOD;  
    }  
}  
  
int main(){  
    long  n, ans;  
  
    init();  
  
    while (cin>>n)  
    {  
        ans = (dp[n][0] + dp[n][1]) % MOD;  
        cout << ans << endl;  
    }  
    return 0;  
}  



注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!

原文地址:http://blog.csdn.net/ebowtang/article/details/50353867

原作者博客:http://blog.csdn.net/ebowtang


你可能感兴趣的:(LeetCode,算法,面试,数学,动态规划)