【动态规划】力扣.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() 的数组,这会带来额外的内存分配和管理开销。新的代码通过使用固定数量的变量来代替数组,避免了这种开销,从而提高了运行效率。

相关推荐
算AI8 小时前
人工智能+牙科:临床应用中的几个问题
人工智能·算法
hyshhhh10 小时前
【算法岗面试题】深度学习中如何防止过拟合?
网络·人工智能·深度学习·神经网络·算法·计算机视觉
杉之10 小时前
选择排序笔记
java·算法·排序算法
烂蜻蜓11 小时前
C 语言中的递归:概念、应用与实例解析
c语言·数据结构·算法
OYangxf11 小时前
图论----拓扑排序
算法·图论
我要昵称干什么11 小时前
基于S函数的simulink仿真
人工智能·算法
AndrewHZ11 小时前
【图像处理基石】什么是tone mapping?
图像处理·人工智能·算法·计算机视觉·hdr
念九_ysl11 小时前
基数排序算法解析与TypeScript实现
前端·算法·typescript·排序算法
守正出琦11 小时前
日期类的实现
数据结构·c++·算法
ChoSeitaku11 小时前
NO.63十六届蓝桥杯备战|基础算法-⼆分答案|木材加工|砍树|跳石头(C++)
c++·算法·蓝桥杯