当前位置: 首页 > news >正文

【算法练习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

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 打家劫舍打家劫舍 II打家劫…...

双十一运动健身好物推荐,这几款健身好物一定不要错过!

双十一购物狂欢节又要到了&#xff0c;又要到买买买的时候了&#xff01;相信有很多想健身的小白还在发愁不知道买啥装备&#xff1f;别急&#xff0c;三年健身达人这就给你们分享我的年度健身好物&#xff01; 第一款&#xff1a;南卡Runner Pro4s骨传导耳机 推荐理由&#…...

Angular异步数据流编程

1 目前常见的异步编程的几种方法 首先给出一个异步请求的实例&#xff1a; import {Injectable} from angular/core;Injectable({providedIn: root }) export class RequestServiceService {constructor() {}getData() {setTimeout(() > {let res zhaoshuai-lcreturn res…...

古典舞学习的独舞与群舞,古典舞的成品舞蹈教学大全

一、教程描述 本套教程的古典舞是很全面的&#xff0c;不仅有舞蹈动作分解教学&#xff0c;而且有成品舞的完整教学&#xff0c;同时提供独立的背景音乐文件&#xff0c;可以让你更快地学会古典舞。本套教程&#xff0c;大小30.54G&#xff0c;共有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标准库中&#xff0c;rust/library/std/src/sync/mpmc/select.rs文件的作用是实现一个多生产者多消费者的选…...

计算机编程软件编程基础知识,中文编程工具下载分享

计算机编程软件编程基础知识&#xff0c;中文编程工具下载分享 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c;象如图这个实例…...

微信小程序里怎么添加砍价活动

随着网络购物的普及&#xff0c;越来越多的消费者开始享受这种方便快捷的购物方式。而在这个大环境下&#xff0c;各种电商活动层出不穷&#xff0c;吸引了众多消费者的关注。而在这些活动中&#xff0c;砍价活动无疑是最受欢迎的一种。今天&#xff0c;我们就来聊一聊如何在小…...

如何在Python爬虫中使用IP代理以避免反爬虫机制

目录 前言 一、IP代理的使用 1. 什么是IP代理&#xff1f; 2. 如何获取IP代理&#xff1f; 3. 如何使用IP代理&#xff1f; 4. 如何避免IP代理失效&#xff1f; 5. 代理IP的匿名性 二、代码示例 总结 前言 在进行爬虫时&#xff0c;我们很容易会遇到反爬虫机制。网站…...

干货丨Linux终端常见用法总结(收藏)

一、前言 熟悉Linux终端的基础用法和常见技巧可以极大提高运维及开发人员的工作效率&#xff0c;笔者结合自身学习实践&#xff0c;总结以下终端用法供同行交流学习。 二、常见用法 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任意文件读取漏洞复现

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现代码审计漏洞点 1.5、深度利用EXP编写 1.6、漏洞挖掘1.7修复建议 1.1、漏洞描述 漏洞名称&#xff1a;MetInfo任意文件…...

3.22每日一题(二重积分求平面区域面积)

先复习求平面积分的公式 注&#xff1a;面对平面积分直接使用二重积分对1求积分即可&#xff1b;所以只需要背二重积分的两个公式&#xff1a; 1、直角坐标下对1积分 2、极坐标下对1积分 xy-1是等轴双曲线&#xff01;&#xff01; 1、先画图定区域 2、选择先对x积分还是先对…...

Hadoop环境搭建

1 Hadoop集群环境搭建概述 所谓集群&#xff0c;就是一组通过网络互联的计算机&#xff0c;集群中的每一台计算机称作一个节点&#xff0c;Hadoop集群搭建就是在这个物理集群之上安装部署Hadoop相关的软件&#xff0c;然后对外提供大数据存储和分析等相关服务。 一个前提&…...

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&#xff1a;字符串通配符 描述 问题描述&#xff1a;在计算机中&#xff0c;通配符一种特殊语法&#xff0c;广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求&#xff1a; 实现如下2个通配符&#xff1a; *&#xff1a;匹配0个…...

第十一章 日志管理

第十一章 日志管理 1日志进程rsyslog 任务一 rsyslog 系统日志管理 ​ 关心问题 哪些程序产生的什么日志放到什么地方 任务一详解 1处理日志的进程 第一类 rsyslog 系统专职日志程序 处理绝大部分日志记录 系统操作有关的信息 如登录信息 程序启动关闭信息 错误喜喜 …...

灯串跨境外贸出口欧美CE认证和UL588报告周期解析

灯串灯具出口欧盟要做CE认证&#xff0c;CE认证需要做CE的两项检测,工作电压直流75V以上&#xff0c;交流50V以上 测试EMCLVD两项。 灯串LVD(安规&#xff09;标准为&#xff1a; 欧洲EN 60598-2-20:2015 1.标记 2.结构 3.爬电距离和电气间隙 4.接线端子 5.外部接线和内…...

大数据中的分布式文件系统MapReduce的选择题

一 . 选择题 一. 单选题&#xff08;共9题&#xff0c;49.5分&#xff09; (单选题)下列传统并行计算框架,说法错误的是哪一项? A. 刀片服务器、高速网、SAN,价格贵,扩展性差上 B. 共享式(共享内存/共享存储),容错性好 C. 编程难度高 D. 实时、细粒度计算、计算密集型 正确答…...

storm安装手册及笔记

图解Storm相关概念 图解storm的并发机制 安装Storm的步骤 1、安装一个zookeeper集群 2、上传storm的安装包&#xff0c;解压 3、修改配置文件storm.yaml #所使用的zookeeper集群主机 storm.zookeeper.servers: - "weekend05" - "weekend06"…...

vue 视频流播放

采用的技术是vueflv.js 前言 常见视频流格式 ● RTMP&#xff08;推流端、拉流端&#xff09; ● RTSP&#xff08;推流端&#xff09; ● HLS&#xff08;拉流端&#xff09; ● FLV&#xff08;拉流端&#xff09; 视频流是否依赖插件直播/点播协议web/移动端flv否直播点播…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...