【动态规划】力扣.213. 打家劫舍 II

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

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

示例 1:

输入:nums = [2,3,2]

输出:3

解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入:nums = [1,2,3,1]

输出:4

解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。

偷窃到的最高金额 = 1 + 3 = 4 。

示例 3:

输入:nums = [1,2,3]

输出:3

代码

cpp 复制代码
class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.empty()){
            return 0;
        }
        if(nums.size() == 1){
            return nums[0];
        }
        vector<int>dp1(nums.size());
        int count1 = 0;
        //第一个房子被偷,最后一个房子不被偷
        dp1[0] = nums[0];
        dp1[1] = nums[0];
        for(int i = 2;i < nums.size();i++){
            dp1[i] = max(dp1[i - 2] + nums[i], dp1[i - 1]);
        }
        count1 = dp1[nums.size() - 2];
        
        //第一个房子不被偷,最后一个房子不一定被偷
        vector<int>dp2(nums.size());
        int count2 = 0;
        dp2[0] = 0;
        dp2[1] = nums[1];
        for(int i = 2;i < nums.size();i++){
            dp2[i] = max(dp2[i - 2] + nums[i], dp2[i - 1]);
        }
        count2 = dp2[nums.size() - 1];
        return max(count1,count2);
    }
};

时间复杂度O(n);
空间复杂度O(n);

具体步骤和思路跟打家劫舍1的相同(主页有打家劫舍1的三种算法的详细思路),唯一区别是增加了首尾房子不能同时被偷的限制,所以可以分类讨论,然后返回出能偷到最大的金额即可。

根据上面代码可以发现空间复杂度O(n)来源于vector<int>dp1(nums.size()); ,可以进一步优化成O(1)。

优化代码

cpp 复制代码
class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.empty()){
            return 0;
        }
        if(nums.size() == 1){
            return nums[0];
        }

        int count1 = 0;
        //第一个房子被偷,最后一个房子不被偷
        int first = nums[0];
        int second = nums[0];
        for(int i = 2;i < nums.size();i++){
            int temp = second;
            second = max(first + nums[i], second);
            first = temp;
        }
        count1 = first;
        
        //第一个房子不被偷,最后一个房子不一定被偷
        vector<int>dp2(nums.size());
        int count2 = 0;
        first = 0;
        second = nums[1];
        for(int i = 2;i < nums.size();i++){
            int temp = second;
            second = max(first + nums[i], second);
            first = temp;
        }
        count2 = second;
        return max(count1,count2);
    }
};

时间复杂度:O(n);
空间复杂度:O(1);

旧的代码在计算 dp1 和 dp2 时需要动态分配两个大小为 nums.size() 的数组,这会带来额外的内存分配和管理开销。新的代码通过使用固定数量的变量来代替数组,避免了这种开销,从而提高了运行效率。

相关推荐
宇柔5 分钟前
Day5:移除链表元素
数据结构·算法·链表
Amor风信子23 分钟前
【力扣】2376. 统计特殊整数
算法·leetcode·职场和发展
极客小张23 分钟前
基于正点原子Linux开发板的智能监控与家电控制系统设计:深度解析Video4Linux和TCP/IP技术栈
linux·运维·c++·物联网·网络协议·tcp/ip·算法
JustCouvrir1 小时前
代码随想录算法训练营Day5
算法
周哈里窗的编程2 小时前
CSP-CCF★201912-2回收站选址★
c++·算法·图论
SpongeG3 小时前
数据结构第三周做题总结_链表
数据结构·算法·链表
everyStudy3 小时前
前端五种排序
前端·算法·排序算法
little redcap5 小时前
第十九次CCF计算机软件能力认证-乔乔和牛牛逛超市
数据结构·c++·算法
muyierfly6 小时前
34.贪心算法1
算法·贪心算法
luthane8 小时前
python 实现average mean平均数算法
开发语言·python·算法