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

相关推荐
小白菜又菜1 小时前
Leetcode 3432. Count Partitions with Even Sum Difference
算法·leetcode
wuhen_n2 小时前
LeetCode -- 15. 三数之和(中等)
前端·javascript·算法·leetcode
sin_hielo2 小时前
leetcode 2483
数据结构·算法·leetcode
Xの哲學3 小时前
Linux多级时间轮:高精度定时器的艺术与科学
linux·服务器·网络·算法·边缘计算
大头流矢3 小时前
归并排序与计数排序详解
数据结构·算法·排序算法
油泼辣子多加4 小时前
【信创】算法开发适配
人工智能·深度学习·算法·机器学习
Aaron15884 小时前
AD9084和Versal RF系列具体应用案例对比分析
嵌入式硬件·算法·fpga开发·硬件架构·硬件工程·信号处理·基带工程
laocooon5238578864 小时前
插入法排序 python
开发语言·python·算法
wuhen_n5 小时前
LeetCode -- 1:两数之和(简单)
javascript·算法·leetcode·职场和发展
林shir6 小时前
Java基础1.7-数组
java·算法