Leetcode:198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III(C++)

news2024/11/23 9:24:10

目录

198. 打家劫舍

问题描述:

实现代码与解析:

动态规划(版本一):

原理思路:

动态规划(版本二):

原理思路:

213. 打家劫舍 II

问题描述: 

实现代码与解析:

动态规划:

原理思路:

337. 打家劫舍 III

问题描述:

实现代码与解析:

动态规划(树形dp):

 原理思路:


198. 打家劫舍

问题描述:

        你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

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

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

实现代码与解析:

动态规划(版本一):

class Solution {
public:
    int rob(vector<int>& nums)
    {
        //先把前两个单独弄出来返回
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];

        //dp含义, 按顺序偷第 i 个屋子时获得的最大金额
        vector<int> dp(nums.size(), 0);//dp数组
        dp[0] = nums[0]; // 初始化
        dp[1] = nums[1];

        //遍历
        for (int i = 2; i < nums.size(); i++)
        {
            //小于 3 的时候只能跳一个,所以单独计算一下喽
            if (i < 3) dp[i] = dp[i - 2] + nums[i];
            else
            {
                //跳一个或则跳两个,不能再多跳了,不然肯定会少偷,这两之间取最大喽
                dp[i] = max(dp[i - 2] + nums[i], dp[i - 3] + nums[i]);
                // 偷 i - 2的屋子时获得的最大金额,加上此屋子的金额,和偷 i - 3 的屋子时获得的最大金额加上此屋子金额取最大
            }

        }

        int result = max(dp[nums.size() - 1], dp[nums.size() - 2]);//倒数第一个和倒数第二个比较,因为最后偷的肯定是这两个房间之一
        return result;
    }
};

原理思路:

        这里dp数组的含义是偷第 i 个屋子后能获得的最大价值,有点像爬梯子,大家看注释就能懂,但是其实是写的麻烦了,所以大家看版本二就可以了,要简洁很多。

动态规划(版本二):

class Solution {
public:
    int rob(vector<int>& nums)
    {
        //先把前两个单独弄出来返回
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];

        //dp含义, 按顺序选择0~i的屋子是否偷取时获得的最大金额
        vector<int> dp(nums.size(), 0);//dp数组
        //初始化
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]);
        for(int i = 2; i < nums.size(); i++)
        {
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[nums.size() - 1];
    }
};

原理思路:

        这里dp数组的含义是在1 ~ i 之间选择能获取的最大金额。

        所以房间有两种状态,一种是偷,那么我们就找出 i - 1 能获取的最大金额,然后加上 nums[ i ]就为此时的如果偷的最大金额,一种是不偷,那么我们肯定是偷了 i - 1 编号的房间,此时dp[ i - 1] 为不偷的最大价值,两个之间进行比较,就求出了对于 i 房间偷或不偷选择出的最大金额,也就是dp[ i ]了。   

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

实现代码与解析:

动态规划:

class Solution {
public:
    int robRange(vector<int>& nums,int start,int end)
    {
        if(start == end) return nums[start];// 只有一种元素

        vector<int> dp(nums.size());
        dp[start] = nums[start]; // 初始化
        dp[start + 1] = max(nums[start], nums[start + 1]);
        for(int i = start + 2; i <= end; i++)
        {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp[end];
    }
    int rob(vector<int>& nums) 
    {
        if(nums.size() == 0) return 0;
        if(nums.size() == 1) return nums[0];
        int result1 = robRange(nums, 0, nums.size() - 2); // 不选取最后有一个房间的最大价值
        int result2 = robRange(nums, 1, nums.size() - 1);   // 不选取第一个房间的最大价值

        int result = max(result1, result2);
        return result;

    }
};

原理思路:

        相比于打家劫舍Ⅰ了一个限制条件,就是房屋练成环了,所以无非就两种情况,一种是首尾两个房间都不偷,一种是首尾两个房间偷其中一个,根据Ⅰ的思路我们只要算出,不选取最后一个房间的最大金额和不选取第一个房间的最大金额,两个之中取最大就可以了,所以就比Ⅰ多了个选最大的操作而已,其他相似照着写就行。

337. 打家劫舍 III

问题描述:

        小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。

除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。

给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

示例 1:

输入: root = [3,2,3,null,3,null,1]
输出: 7 
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7

示例 2:

 

输入: root = [3,4,5,1,3,null,1]
输出: 9
解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9s

实现代码与解析:

动态规划(树形dp):

class Solution {
public:
    //dp数组含义,0为不偷cur房间,1为偷cur房间
    vector<int> robTree(TreeNode* cur)
    {
        //没有房间,返回0
        if(cur == NULL) return vector<int>{0,0};
        //左右子树偷或不偷的最大金额
        vector<int> leftDp = robTree(cur -> left);
        vector<int> rightDp = robTree(cur -> right);

        int value1 = leftDp[0] + rightDp[0] + cur -> val;// 此房间偷,那么其子树肯定不偷
        int value2 = max(leftDp[0], leftDp[1]) + max(rightDp[0], rightDp[1]);//不偷cur,此时判断其左右子树偷或不偷的最大值,不要认为一定偷子树就为最大值,一定要比较一下
        return {value2, value1};
    }
    int rob(TreeNode* root) 
    {
        vector<int> result = robTree(root);
        return max(result[0], result[1]);
    }
};

 原理思路:

        这里房间的连接变为二叉树的连接方式了,题目描述还是相连接的不能一起偷。

        这里我们的dp数组的含义就发生改变了,dp为一个长度为2的数组,dp[ 0 ]表示不偷当前房间的最大金额,dp[ 1 ]表示偷当前房间的最大金额,并且作为返回值。

        首先偷当前房间的递推公式好写,偷此房间,那么其孩子结点一定不偷:

dp[ 1 ] = leftDp[0] + rightDp[0] + cur -> val;

        而不偷当前房间的话,我们就要比较孩子结点偷或不偷的最大金额了,取最大,注意不要认为偷孩子结点就是最大金额,这是一个误区,一定要比较一下,万一孩子结点的孩子结点和大于孩子结点呢?此时的递推公式为:

dp[ 0 ] = max(leftDp[0], leftDp[1]) + max(rightDp[0], rightDp[1]);

        还有就是这里肯定是后序遍历,我们要知道孩子结点的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/346646.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

消息中间件----内存数据库 Redis7(第2章 Redis 的安装与配置)

这里是要将 Redis 安装到 Linux 系统中。2.1Redis 的安装2.1.1 克隆并配置主机我这里面的虚拟机里面已经安装过CentOS7系统 在这个系统里面已经关闭了防火墙 已经安装过jdk tomcat maven mysql maven现在我们克隆出来修改名字vim /etc/hostname键盘输入i改成redisesc :wqvim …

Python 类属性与实例属性

原文链接&#xff1a;https://blog.csdn.net/windyJ809/article/details/118197946 首先我们简要说下类属性与实例属性在概念上的不同之处&#xff1a; 类属性是在类中定义的属性&#xff0c;它是和这个类所绑定的&#xff0c;这个类中的所有对象都可以访问。访问时可以通过类…

Android NFC 标签读写Demo与历史漏洞概述

文章目录前言NFC基础1.1 RFID区别1.2 工作模式1.3 日常应用NFC标签2.1 标签应用2.2 应用实践2.3 标签预览2.4 前台调度读写Demo历史漏洞总结前言 NFC 作为 Android 手机一个重要的短距特性&#xff0c;基本在所有 Android 中高端机型上均有支持&#xff0c;但说实话本人原先却…

存储硬件与协议

存储硬件与协议存储设备的历史轨迹存储介质的进化3D NAND3D XPointIntel Optane存储接口协议的演变NVMeNVMe-oF网络存储技术1&#xff09;DAS2&#xff09;NAS3&#xff09;SAN4&#xff09;iSCSIiSCSI层次结构存储设备的历史轨迹 1.穿孔卡2.磁带3.硬盘4.磁盘&#xff08;软盘…

【2023】【standard-products项目】中查找的问题与解决方案 (未完待续)

10、el-table 判断是多选操作还是单选操作 9、判断数组对象中是否包含某个指定值 需求&#xff1a;修改时数据回填el-select下拉数据&#xff0c;发现当前id在原数组里没有找到&#xff0c;就显示了id值&#xff0c;应该显示name名&#xff0c; 处理&#xff1a;当查找到id…

向量与矩阵 导数和偏导数 特征值与特征向量 概率分布 期望方差 相关系数

文章目录向量与矩阵标量、向量、矩阵、张量向量范数和矩阵的范数导数和偏导数特征值和特征向量概率分布伯努利分布正态分布&#xff08;高斯分布&#xff09;指数分布期望、⽅差、协⽅差、相关系数期望方差协⽅差相关系数向量与矩阵 标量、向量、矩阵、张量 标量&#xff08;…

源码系列 之 ThreadLocal

简介 ThreadLocal的作用是做数据隔离&#xff0c;存储的变量只属于当前线程&#xff0c;相当于当前线程的局部变量&#xff0c;多线程环境下&#xff0c;不会被别的线程访问与修改。常用于存储线程私有成员变量、上下文&#xff0c;和用于同一线程&#xff0c;不同层级方法间传…

Jenkins 笔记

Jenkins brew install jenkins-lts brew services restart jenkins-lts brew services stop jenkins-lts b999ff5683464346b6d083f894968121 l 软件构建自动化 &#xff1a;配置完成后&#xff0c;CI系统会依照预先制定的时间表&#xff0c;或者针对某一特定事件&#xff0c;…

进阶C语言第三章-------《字符函数和内存函数》 完整思维导图+基本练习题+深入细节+通俗易懂+知识点+建议收藏

绪论 书接上回&#xff0c;通过进阶指针你已经了解到了更多种指针类型&#xff0c;他们的用法及使用之处相当的关阔需要不断的积累经验来使用&#xff0c;这里我毛遂自荐一下我的指针练习希望对你有帮助&#xff0c;本章是一些关于字符串的函数介绍和自己实现&#xff0c;总体来…

数据结构与算法基础-学习-11-线性表之链栈的初始化、判断非空、压栈、获取栈长度、弹栈、获取栈顶元素

一、个人理解链栈相较于顺序栈不存在上溢&#xff08;数据满&#xff09;的情况&#xff0c;除非内存不足&#xff0c;但存储密度会低于顺序栈&#xff0c;因为会多存一个指针域&#xff0c;其他逻辑和顺序表一致。总结如下&#xff1a;头指针指向栈顶。链栈没有头节点直接就是…

智慧校园应用系统建设方案

系统简介 建设“智慧校园”的核心是创新新形势下高校发展理念、推进高校建设转型、变革高校管理行为方式&#xff1b;建设“智慧校园”的目的是推进信息化进入高校、服务管理、惠及师生&#xff1b;建设“智慧”的目标是实现 “信息采集、数据整合、信息促管、信息育人、信息联…

linux之echo使用技巧

参考文章&#xff1a;linux基本功系列-echo命令实战一、echo 命令是什么&#xff1f;作用&#xff1a; echo命令能将指定文本显示在Linux命令行上&#xff0c;或者通过重定向符写入到指定的文件中。语 法&#xff1a;echo [-ne][字符串] / echo [–help][–version]补充说明&am…

VMware安装CentOS7

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。个人爱好: 编程&#xff0c;打篮球&#xff0c;计算机知识个人名言&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石…

Java+Python+HanLP自然语言处理包实现解析文本分词

目录 需要安装 Python部分 Java部分 需要安装 HanLP官网Api教程 https://bbs.hanlp.com/t/hanlp2-1-restful-api/53 首先需要电脑安装Python环境并配置环境变量&#xff08;网上搜就可以一大堆教程&#xff09;&#xff0c;建议Python版本3 然后根据HanLP官网教程安装hanl…

「JVM 原理使用」 实际开发中的应用

Class 文件格式、执行引擎主要以 Class 文件描述了存储格式、类何时加载、如何连接、VM 如何执行字节码指令&#xff0c;这些动作基本都是 JVM 直接控制&#xff0c;用户代码无法干预和改变&#xff1b; 用户可以干预的只有字节码生成、类加载器两部分&#xff0c;而这两部分的…

Android 面试 基础知识汇总

Android常用的设计模式HTTP和HTTPS的区别TCP/UDP的区别

PendingIntent兼容安卓12 的一个问题

这是我第一次遇到这个问题&#xff0c;反正我也是第一次做完整的安卓app&#xff0c;很多个第一次。我之前做的那个老旧手机做桌面摆件的app&#xff0c;因为原来的“无干预”版本无法使用&#xff0c;所以又用回了“和风版”&#xff0c;但这个版本很久没用了&#xff0c;有些…

实用机器学习-学习笔记

文章目录9.1模型调参9.1.1思考与总结9.1.2 基线baseline9.1.3SGD ADAM9.1.4 训练代价9.1.5 AUTOML9.1.6 要多次调参管理9.1.7复现实验的困难9.1模型调参 9.1.1思考与总结 1了解了baseline和调参基本原则 2了解了adams和sgd的优劣 3了解了训练树和神经网络的基本代价 4了解了a…

【蓝桥杯集训2】差分专题(3 / 4)

目录 差分模板 1、一维差分 2、二维差分 3729. 改变数组元素 - 差分 区间修改 100. 增减序列 - 差分模板 1、一维差分 活动 - AcWing 给a数组 [l,r] 区间的每个数c&#xff0c;只需要给其差分数组b做如下操作即可 b[l]c; b[r1]-c; 差分数组 a[]是b[]的前缀和数组 如果…

倒计时100天 | DBF深圳国际户外运动博览会5月一起狂飙初夏

狂飙初夏的大型户外运动嘉年华即将登场&#xff01;2023年5月26日至28日&#xff0c;第四届DBF深圳国际户外运动博览会&#xff08;简称DBF深圳户外展&#xff09;将于深圳国际会展中心&#xff08;宝安&#xff09;举办。本届展会展览面积超过7万平方米&#xff0c;预计将吸引…