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

相关推荐
The_Ticker13 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
Lenyiin1 小时前
02.06、回文链表
数据结构·leetcode·链表
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
Dola_Pan1 小时前
C语言:数组转换指针的时机
c语言·开发语言·算法
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
烦躁的大鼻嘎1 小时前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode
C++忠实粉丝2 小时前
计算机网络socket编程(4)_TCP socket API 详解
网络·数据结构·c++·网络协议·tcp/ip·计算机网络·算法
祁思妙想2 小时前
10.《滑动窗口篇》---②长度最小的子数组(中等)
leetcode·哈希算法
用户37791362947552 小时前
【循环神经网络】只会Python,也能让AI写出周杰伦风格的歌词
人工智能·算法
福大大架构师每日一题2 小时前
文心一言 VS 讯飞星火 VS chatgpt (396)-- 算法导论25.2 1题
算法·文心一言