leetcode 213. 打家劫舍II

题目描述:

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

思路:与上一题“打家劫舍”相比,唯一的变化在于房屋围成了一圈。类似上一篇,假定总共有n间房子(0~n-1号),考察0号房间和1号房间,如果第一步选择0号房间,那么一定不会选与之相邻的n-1号房间。这样问题演化为偷取0~n-2号房间。如果第一步选择1号房间,问题同样转化为偷取1~n-1号房间。这样就把一个问题划分成了两个子问题,我们可以分别求出它们的最优解,然后再取更好的那个。

但是还有个问题:偷取0~n-2号房间时的最优解,不一定会偷取0号房间啊?这与我们的假设(第一步一定偷取0号房)不相符,会不会导致错过最优解?这个担心是多余的。如果最优解中没有偷取0号房间,那么最优解必然是1~n-1号房间问题的最优解;否则它就是0~n-2号房间问题的最优解。所以无论如何,最优解都会被找到。

这两个子问题性质与上一个问题“打家劫舍”相同,所以也采用了相同的解法。

int rob(vector<int>& nums) {
        int n=nums.size();
        if(n==0) return 0;
        if(n==1) return nums[0];
        //注:m[i]代表从房间i出来时,身上的金钱总量
        vector<int> m(n);
        //情况1,偷0~n-2号房间
        m[0]=nums[0],m[1]=max(nums[0],nums[1]);
        for(int i=2;i<n-1;i++)
            m[i]=max(m[i-1],m[i-2]+nums[i]);
        int ans1=m[n-2];
        
        //情况2,偷1~n-1号房间
        m[1]=nums[1],m[2]=max(nums[1],nums[2]);
        for(int i=3;i<n;i++)
            m[i]=max(m[i-1],m[i-2]+nums[i]);
        int ans2=m[n-1];
        //返回总问题的最优解
        return max(ans1,ans2);
    }

测试运行时间0ms,难以置信。算法时间复杂度和空间复杂度都是O(n)。空间可以优化到O(1),但是那样会使时间复杂度的常数项系数增大,损失一些时间上的性能。

猜你喜欢

转载自blog.csdn.net/liusiweix/article/details/84112663
今日推荐