【算法练习Day40】打家劫舍打家劫舍 II打家劫舍 III

📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待
文章目录
- 打家劫舍
- 打家劫舍 II
- 打家劫舍 III
- 总结:
这一期到了打家劫舍的专题,说是专题但实际上只有一期,而且只有三道题,我们把这三道题放在一起讲,第一道题简单一些,后两道略有不同方向上的难度。但总体来看第一次做可能有一点难想到思路,其实代码实现还是可以的。
打家劫舍
198. 打家劫舍 - 力扣(LeetCode)
题目要求相邻两间房子不能同时遭到盗窃。根据这一条件能够想清如何写出递推公式,则是解题的关键。
dp数组的含义:dp【i】代表了考虑当前第i个位置,是否被偷盗,所能盗得的最大金钱数,注意这里仅仅是考虑这个位置房子是否被偷盗,但是并不是一定会盗窃该房屋,具体是否盗窃该房屋,由递推公式决定。
递推公式: 对于此时遍历到的位置i有两种状态,偷或者不偷,如果是偷那么一定是当前房子被偷获得的价值nums【i】加上当前位置向前数的第二个位置所能获得的最大价值(同样的这个位置也不一定被偷)也就是dp【i-2】,偷该房子的最大获得钱币变成了nums【i】+dp【i-2】,如果不偷该房子,那么该房子的前一个位置就可以被考虑进来是dp【i-1】,它们两个取最大值
dp【i】=max(dp【i-2】+nums【i】,dp【i-1】)。这就是递推公式
我们要时刻记得当前位置i只是被考虑进来偷或者不偷,在递推公式取最大值之前,不能确定该位置一定偷或者不偷。
dp数组的初始化:dp【0】也就是起始位置,我们可以这样假想,加入房子只有一间,那么一定是偷盗了,才能获得最大金钱,所以dp【0】=nums【0】,我们还得为dp【1】初始化,因为递推公式需要用到i的前两个位置,dp【1】=max(nums【0】,nums【1】)是这两个屋子取最大值偷,因为相邻房子不能同时偷,同样可以想成一共只有两个房子,我们考虑偷第一间还是第二间。其余的位置初始化什么数都可以,因为并不能影响最后的答案。
遍历顺序:从前到后,很自然的遍历顺序,并没有考究。
class Solution {
public:int rob(vector<int>& nums) {if(nums.size()==0)return 0;if(nums.size()==1)return nums[0];vector<int>dp(nums.size(),0);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】初始化为nums【1】,然后最后比较的是偷第一间房屋和不偷哪个价值更大,这样做实际上是有弊端的例如测试用例为{2,1,1,2}时,这种情况是中间两间房子不偷盗,而两边偷盗获得的多。题目虽然要求相邻房子不能偷,但是这并不意味着我们一定要不停偷取才能获得最大金钱!!这就是曲解了dp数组的含义,dp【i】应是考虑i这个位置,而不是一定偷盗,这样想的才能解决这样的测试用例。
下面也给出错误的代码
class Solution {
public:int rob(vector<int>& nums) {if(nums.size()==0)return 0;if(nums.size()==1)return nums[0];vector<int>dp(nums.size(),0);dp[0]=nums[0];dp[1]=nums[1];for(int i=2;i<nums.size();i++){dp[i]=max(dp[i-2]+nums[i],dp[i-1]);}return max(dp[nums.size()-1],dp[nums.size()-2]);}
};
相信对于上面的详细讲解,大家也对于这类问题的入门题目有了一定的了解,下面看一个进阶版本的。
打家劫舍 II
213. 打家劫舍 II - 力扣(LeetCode)
这道题的题目和上一道的唯一区别,在于房子围成一周,第一间房子与最后一间连接起来,并且也不能同时取。线性问题的数组,我们容易想到解题思路,那么环形的我们该如何思考呢?
将该环形数组分为三种情况,我们可以不看两边的房屋,只考虑中间部分 ,这是一种情况,这样中间部分可以像上一道题的思路一样,很轻松做出来,但是两边房屋该怎么办呢?别急还有另外两种情况,不考虑第一个房屋,和不考虑最后一个房屋。实际上这两种情况都包含了第一种情况,由于我们只是考虑这些房屋是否被偷盗,第二三种方法比第一种方法考虑的范围还要远,所以肯定是包含在内,而又由于第一间房屋和最后一间房屋并不能同时放在一起考虑,因为它们成环相连,所以我们只需取得二三种方法中较大得到金钱的那一个,即为最后的答案。将两个范围带入第一个题的函数中去,取得两个最大金钱值,取较大一个即可,看代码实现。
class Solution {
public:int rob(vector<int>& nums) {if(nums.size()==1)return nums[0];if(nums.size()==0)return 0;int result1=fun(nums,0,nums.size()-2);int result2=fun(nums,1,nums.size()-1);return max(result1,result2);}int fun(vector<int>&nums,int start,int end){if(start==end)return nums[start];//防止数组大小等于2vector<int>dp(nums.size(),0);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-2]+nums[i],dp[i-1]);}return dp[end];}
};
代码实现是不是也很简单?但是想到思路可不是很容易,尤其对于没有做过很多环形数据的题人来说。特别说明:为什么函数实现里多了一个if(start==end)的判断,我们可能会想正常数组怎么可能传进来的的开始和结束指向同一个位置呢?这其实并不是我们传入错误,有些时候数据可能较短,比如只有两个数据的情况,这样的话按照我们上面的思路,就会出现start和end值一样的情况,我们就要直接返回一个数,因为如果这样再往下走会出现数组越界的情况。
这最后一道是二叉树和动态规划的交叉使用例题,也是树形dp的入门题目。这道题要求对于二叉树的使用要娴熟,而且还要穿插上动态规划的使用,第一次做同样也是有难度的例题。
打家劫舍 III
337. 打家劫舍 III - 力扣(LeetCode)
要求同样是相邻房屋不能被连续抢劫,所以就是取父节点就不能取两个子节点了!
前面的dp数组含义是一样的,不同的是递推公式需要注意一点。
我们要写递归函数来遍历整颗二叉树,需要两个dp数组分别代表左子树和右子树对于该节点偷或者不偷的两种情况分别对应的钱数。说一个误区,题目虽然是说一个父节点只有一个孩子节点,那为什么我们还需要两个dp呢?是因为我们不确定下一个子房子是左子树还是右子树上,所以我们要两个dp数组,而且也可能是一会像左一会向右,所以两边都需要记录,但是仅仅是需要每一个dp数组只有两个参数,dp【0】dp【1】,因为每次递归是会向下遍历的,上一层由系统栈存储,不需要担心每一个节点的数据会丢失。如果当前节点,我们选择偷那么值就是root-> val+leftdp【0】+rightdp【0】,因为取这个节点子节点都不能取,如果不取该节点就是leftdp【1】+rightdp【1】,它们两个最后取最大值就可以了。
细心的盆友肯定会发现,leftdp和rightdp的状态在我们遍历当前节点时候,不是还不能确定下来吗?所以这也是说明我们的遍历顺序是从下往上的后序遍历,把下面的状态推给上一层,这样就可以实现上一层的数据处理依赖下一层的数据了。
class Solution {
public:int rob(TreeNode* root) {vector<int>result=fun(root);return max(result[0],result[1]);}vector<int>fun(TreeNode* root){if(root==NULL)return vector<int>{0,0};vector<int>left=fun(root->left);vector<int>right=fun(root->right);int val1=max(left[0],left[1])+max(right[0],right[1]);int val2=root->val+left[0]+right[0];return {val1,val2};}
};
后序遍历的方法,可以让我们从下向上传递状态转移,遇到空子树,返回的相当于取和不取都是0。最后到根节点往上返回根节点取和不取的两种金钱数,取最大。注意return返回的val1,和val2的顺序不能颠倒,他们是有确定的含义的,返回上一层时候需要调用下一层的两个状态,写反了一定会出问题。
最后,对于递归向上返回时是如何工作的,大家可以自行实现一下,不要只知道代码大概模板,就通过了,做递归类问题最重要的是要知道递归每一步是如何返回的,这样更有利于深刻理解。
总结:
今天我们完成了打家劫舍、打家劫舍 II、打家劫舍 III 三道题,相关的思想需要多复习回顾。接下来,我们继续进行算法练习。希望我的文章和讲解能对大家的学习提供一些帮助。
当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

相关文章:
【算法练习Day40】打家劫舍打家劫舍 II打家劫舍 III
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 打家劫舍打家劫舍 II打家劫…...
双十一运动健身好物推荐,这几款健身好物一定不要错过!
双十一购物狂欢节又要到了,又要到买买买的时候了!相信有很多想健身的小白还在发愁不知道买啥装备?别急,三年健身达人这就给你们分享我的年度健身好物! 第一款:南卡Runner Pro4s骨传导耳机 推荐理由&#…...
Angular异步数据流编程
1 目前常见的异步编程的几种方法 首先给出一个异步请求的实例: import {Injectable} from angular/core;Injectable({providedIn: root }) export class RequestServiceService {constructor() {}getData() {setTimeout(() > {let res zhaoshuai-lcreturn res…...
古典舞学习的独舞与群舞,古典舞的成品舞蹈教学大全
一、教程描述 本套教程的古典舞是很全面的,不仅有舞蹈动作分解教学,而且有成品舞的完整教学,同时提供独立的背景音乐文件,可以让你更快地学会古典舞。本套教程,大小30.54G,共有276个文件。 二、教程目录 …...
听GPT 讲Rust源代码--library/std(16)
题图来自 EVALUATION OF RUST USAGE IN SPACE APPLICATIONS BY DEVELOPING BSP AND RTOS TARGETING SAMV71[1] File: rust/library/std/src/sync/mpmc/select.rs 在Rust标准库中,rust/library/std/src/sync/mpmc/select.rs文件的作用是实现一个多生产者多消费者的选…...
计算机编程软件编程基础知识,中文编程工具下载分享
计算机编程软件编程基础知识,中文编程工具下载分享 给大家分享一款中文编程工具,零基础轻松学编程,不需英语基础,编程工具可下载。 这款工具不但可以连接部分硬件,而且可以开发大型的软件,象如图这个实例…...
微信小程序里怎么添加砍价活动
随着网络购物的普及,越来越多的消费者开始享受这种方便快捷的购物方式。而在这个大环境下,各种电商活动层出不穷,吸引了众多消费者的关注。而在这些活动中,砍价活动无疑是最受欢迎的一种。今天,我们就来聊一聊如何在小…...
如何在Python爬虫中使用IP代理以避免反爬虫机制
目录 前言 一、IP代理的使用 1. 什么是IP代理? 2. 如何获取IP代理? 3. 如何使用IP代理? 4. 如何避免IP代理失效? 5. 代理IP的匿名性 二、代码示例 总结 前言 在进行爬虫时,我们很容易会遇到反爬虫机制。网站…...
干货丨Linux终端常见用法总结(收藏)
一、前言 熟悉Linux终端的基础用法和常见技巧可以极大提高运维及开发人员的工作效率,笔者结合自身学习实践,总结以下终端用法供同行交流学习。 二、常见用法 1.快捷键 1.1.Alt. 在光标位置插入上一次执行命令的最后一个参数。 1.2.CtrlR 模糊搜索历…...
【RealTek sdk-3.4.14b】RTL8197FH-VG+RTL8812FR实现实现Host 网络和Guest 网络隔离以及各个连接终端间隔离功能
SDK 说明 ** Gateway/AP firmware v3.4.14b – Aug 26, 2019** Wireless LAN driver changes as: Refine WiFi Stability and Performance Add 8812F MU-MIMO Add 97G/8812F multiple mac-clone Add 97G 2T3R antenna diversity Fix 97G/8812F/8814B MP iss…...
【漏洞复现】Metinfo6.0.0任意文件读取漏洞复现
感谢互联网提供分享知识与智慧,在法治的社会里,请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现代码审计漏洞点 1.5、深度利用EXP编写 1.6、漏洞挖掘1.7修复建议 1.1、漏洞描述 漏洞名称:MetInfo任意文件…...
3.22每日一题(二重积分求平面区域面积)
先复习求平面积分的公式 注:面对平面积分直接使用二重积分对1求积分即可;所以只需要背二重积分的两个公式: 1、直角坐标下对1积分 2、极坐标下对1积分 xy-1是等轴双曲线!! 1、先画图定区域 2、选择先对x积分还是先对…...
Hadoop环境搭建
1 Hadoop集群环境搭建概述 所谓集群,就是一组通过网络互联的计算机,集群中的每一台计算机称作一个节点,Hadoop集群搭建就是在这个物理集群之上安装部署Hadoop相关的软件,然后对外提供大数据存储和分析等相关服务。 一个前提&…...
SpringBoot_mybatis-plus使用json字段
mybatis-plus使用json字段 1.前言2.方案分析2.1 为什么是json2.2 数据库的选择 3. 实战3.1 使用text字段(h2数据库)3.1.1 建表语句3.1.2 数据操作与查询 3.2 使用json字段(mysql数据库)3.2.1 建表语句3.2.2 数据操作与查询 4. 附录4.1 MySQL JSON索引用法4.2 mybatis-plus json…...
牛客出bug(华为机试HJ71)
Hj71:字符串通配符 描述 问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求: 实现如下2个通配符: *:匹配0个…...
第十一章 日志管理
第十一章 日志管理 1日志进程rsyslog 任务一 rsyslog 系统日志管理 关心问题 哪些程序产生的什么日志放到什么地方 任务一详解 1处理日志的进程 第一类 rsyslog 系统专职日志程序 处理绝大部分日志记录 系统操作有关的信息 如登录信息 程序启动关闭信息 错误喜喜 …...
灯串跨境外贸出口欧美CE认证和UL588报告周期解析
灯串灯具出口欧盟要做CE认证,CE认证需要做CE的两项检测,工作电压直流75V以上,交流50V以上 测试EMCLVD两项。 灯串LVD(安规)标准为: 欧洲EN 60598-2-20:2015 1.标记 2.结构 3.爬电距离和电气间隙 4.接线端子 5.外部接线和内…...
大数据中的分布式文件系统MapReduce的选择题
一 . 选择题 一. 单选题(共9题,49.5分) (单选题)下列传统并行计算框架,说法错误的是哪一项? A. 刀片服务器、高速网、SAN,价格贵,扩展性差上 B. 共享式(共享内存/共享存储),容错性好 C. 编程难度高 D. 实时、细粒度计算、计算密集型 正确答…...
storm安装手册及笔记
图解Storm相关概念 图解storm的并发机制 安装Storm的步骤 1、安装一个zookeeper集群 2、上传storm的安装包,解压 3、修改配置文件storm.yaml #所使用的zookeeper集群主机 storm.zookeeper.servers: - "weekend05" - "weekend06"…...
vue 视频流播放
采用的技术是vueflv.js 前言 常见视频流格式 ● RTMP(推流端、拉流端) ● RTSP(推流端) ● HLS(拉流端) ● FLV(拉流端) 视频流是否依赖插件直播/点播协议web/移动端flv否直播点播…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
