打劫房屋

来源:互联网 发布:手机windows模拟器 编辑:程序博客网 时间:2024/04/27 11:58

打劫房屋 I II

打劫房屋I

描述

假设你是一个专业的窃贼,准备沿着一条街打劫房屋。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,系统会自动报警。

给定一个非负整数列表,表示每个房子中存放的钱,算一算,如果今晚去打劫,你最多可以得到多少钱,在不触动报警装置的情况下。

样例

给定 [3, 8, 4], 返回 8.

挑战

O(n) 时间复杂度 且 O(1) 存储。

递归+缓存方法

class Solution {public:    /**     * @param A: An array of non-negative integers.     * return: The maximum amount of money you can rob tonight     * 思路一:直接写递推方程,dp[n]数组保存打劫前n个房间的总价值     * 思路二:按照求解的基本步骤,先递归,再去雍余,然后计划搜索     */     int *dp;    long long search(int n,vector<int> &A)    {        if(n==0)//如果只有一个元素,返回第一个值            return A[0];        if(dp[n]>=0)//如果已经计算过打劫前n个房屋能获得的最大价值,直接返回(去雍余)            return dp[n];        dp[n]= max(search(n-1,A),search(n-2,A)+A[n]);//因为不能打劫相邻的房屋,故前        //n个的最大价值应该是max{打劫前n-1个房屋,打劫前n-2个房屋+第n个房屋的价值)        return dp[n];    }    long long houseRobber(vector<int> A) {        // write your code here        if(A.size()<0)//边界条件,直接返回            return 0;        dp=new int[A.size()];//保存计算过的中间状态,也是缓存的方法        for(int i=0;i<A.size();++i)            dp[i]=INT_MIN;//因为是求解最大值,故初始化为-无穷小        long long result=search(A.size()-1,A);//求解打劫n个房屋获取的最大财富        delete []dp;        return result;    }};

这种方法求解超时,Time Limit Exceeded 总耗时:1272 ms,82% 数据通过测试.

动态规划方法求解:

Accepted 总耗时: 659 ms

class Solution {public:    /**     * @param A: An array of non-negative integers.     * return: The maximum amount of money you can rob tonight     * 法二:动态规划求解     * 递推方程:dp[n]=max{dp[n-1],dp[n-2]+A[n]};//因为不能打劫相邻的房屋     * dp[i]表示打劫qiani个房屋所能获取的最大财富     */    long long houseRobber(vector<int> A) {        // write your code here        long long dp[A.size()];        //边界条件        if(A.size()<0)            return 0;        if(A.size()==0)            return A[0];        dp[0]=A[0];        dp[1]=max(A[0],A[1]);        //顺序求解dp[2...n-1]        for(int i=2;i<A.size();++i)        {            dp[i]=max(dp[i-1],dp[i-2]+A[i]);//递推方程,用题意推出,用动态规划求解的关键        }        return dp[A.size()-1];//返回最后的结果    }};

打劫房屋 II

描述

在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。

给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

注意事项

这题是House Robber的扩展,只不过是由直线变成了圈

样例

给出nums = [3,6,4], 返回 6,你不能打劫3和4所在的房间,因为它们围成一个圈,是相邻的.

class Solution {public:    /**     * @param nums: An array of non-negative integers.     * return: The maximum amount of money you can rob tonight     *思路:与打劫房屋1不同的是,这次最后一个房屋不可能和第一个房屋一起打劫     * 故打劫房屋第0个房间到第n-1个房间问题转换成求解     * max{打劫房屋第0个房间到第n-2个房间,打劫房屋第1间到第n-1间房屋}     * 简单的来说:对于第0间和第n-1间的关系就是-->有他没我,有我没他     * 继续使用动态规划求解,递推方程如下:     * dp[i]=max{dp[i-1],dp[i-2]+nums[i]} i>=2     */    //serach()函数返回的是从指定下标房间号start位置到下标n位置打劫的最大财富    int search(const vector<int> &nums,int start,int n)    {        //start代表起始房间下标,n代表可以打劫到最后一个房间的下标        vector<int>dp(n+1,INT_MIN);//保留求解子问题的最优解,注意,开辟空间为n+1        if(n<1)//边界条件,只有一个房间,直接返回            return nums[start];        dp[start]=nums[start];//只有一个房间时        dp[start+1]=max(nums[start],nums[start+1]);//只有两个房间时        for(int i=start+2;i<=n;++i)            dp[i]=max(dp[i-1],dp[i-2]+nums[i]);        return dp[n];//dp[n]保存的就是打劫从第start下标开始的房间号到第n间得到的总财富    }    int houseRobber2(vector<int>& nums) {        // write your code here        int n=nums.size();        int result1=0;//result1用来保存打劫第0间到第n-2间的最大财富        int result2=0;//result2用来保存打劫第1间到第n-1间的最大财富        //边界条件        if(n<0)            return 0;        if(n==1)//如果只有一个元素,直接返回此元素的值            return nums[0];        result1=search(nums,0,n-2);        result2=search(nums,1,n-1);        return result1>result2 ? result1:result2;    }};
1 0
原创粉丝点击