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

相关推荐
游是水里的游14 分钟前
【算法day19】回溯:分割与子集问题
算法
不想当程序猿_15 分钟前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
南城花随雪。34 分钟前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
dundunmm1 小时前
机器学习之scikit-learn(简称 sklearn)
python·算法·机器学习·scikit-learn·sklearn·分类算法
古希腊掌管学习的神1 小时前
[机器学习]sklearn入门指南(1)
人工智能·python·算法·机器学习·sklearn
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
KpLn_HJL2 小时前
leetcode - 2139. Minimum Moves to Reach Target Score
java·数据结构·leetcode
程序员老冯头3 小时前
第十五章 C++ 数组
开发语言·c++·算法
AC使者7 小时前
5820 丰富的周日生活
数据结构·算法
cwj&xyp8 小时前
Python(二)str、list、tuple、dict、set
前端·python·算法