第四十七天| 198.打家劫舍、213.打家劫舍II、337.打家劫舍III

Leetcode 198.打家劫舍

题目链接:198 打家劫舍

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

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

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 400

思考:动态规划。难点:当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷。

  • 确定dp数组(dp table)以及下标的含义

dp[i]:下标i(包括i)以内的房屋,偷窃的最高金额。

  • 确定递推公式

决定dp[i]的因素就是第i房间偷还是不偷。

如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。

如果不偷第i房间,那么dp[i] = dp[i - 1],即考 虑i-1房。

并且dp[i]取最大值,则dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);

  • dp数组如何初始化

从递推公式dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);可以看出,递推公式的基础就是dp[0] 和 dp[1]

从dp[i]的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);

  • 确定遍历顺序

由于dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历。

  • 例推导dp数组

举例:[2,7,9,3,1]。dp状态如图:

代码:

class Solution {
public:int rob(vector<int>& nums) {if (nums.size() == 0)   return 0;           //情况一:数组长度为0if (nums.size() == 1)   return nums[0];     //情况二:数组长度为1vector<int> dp(nums.size());     //下标i(包括i)以内的房屋,偷窃的最高金额dp[0] = nums[0];dp[1] = max(nums[0], nums[1]);for (int i = 2; i < nums.size(); i++)      //遍历房间dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);return dp[nums.size() - 1]; }
};

Leetcode 213.打家劫舍II

题目链接:213 打家劫舍II

题干:你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

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

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 1000

思考:动态规划。本题和上题的唯一区别就是成环。

对于一个数组,成环的话主要有如下三种情况:

  • 情况一:考虑不包含首尾元素

  • 情况二:考虑包含首元素,不包含尾元素

  • 情况三:考虑包含尾元素,不包含首元素

情况二 和 情况三 都包含了情况一,所以只需要用上题的处理逻辑考虑情况二和情况三即可,返回最大值。 

代码:

class Solution {
public://打家劫舍的逻辑int robRange(const vector<int>& nums, int start, int end) {if (start == end)   return nums[start];     //打劫区间为1vector<int> dp(nums.size());     //下标i(包括i)以内的房屋,偷窃的最高金额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;                       //情况一:数组长度为0if (nums.size() == 1)   return nums[0];                 //情况二:数组长度为1int result1 = robRange(nums, 0, nums.size() - 2);       //情况三:不考虑最后的房间int result2 = robRange(nums, 1, nums.size() - 1);       //情况四:不考虑首个房间return max(result1, result2);}
};

Leetcode  337.打家劫舍III

题目链接:337 打家劫舍III

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

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

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

  • 树的节点数在 [1, 104] 范围内
  • 0 <= Node.val <= 104

思考一:递归法 + 暴力法。终止条件:如果当前节点为空,则返回0。如果当前节点为叶子节点,则不用处理直接返回此节点值即可。

 单层递归逻辑:考虑两种情况。情况一:偷根节点,由于相邻节点不能都偷,因此递归处理左右孩子节点的孩子节点,并累加值、记录到val1。情况二:不偷根节点,则递归处理左右孩子节点,并累加值,记录到val2。取val1和val2的较大值返回。

按以上方式处理会超时,因此要添加备忘录,用于记录每个子树盗取的最高金额。当然单层递归逻辑要将上面的最大值记录下。此外终止条件要加上如果备忘录记录过,则返回记录数据。

代码:

class Solution {
public:unordered_map<TreeNode*, int> memo;     //备忘录 记录每个子树盗取的最高金额int rob(TreeNode* root) {if (!root)  return 0;       //空节点返回0if (!root->left && !root->right)    return root->val;       //叶子节点返回节点值if (memo[root]) return memo[root];      //备忘录中添加过则直接返回数据//偷根节点int val1 = root->val;if (root->left) val1 += rob(root->left->left) + rob(root->left->right);      //不偷左孩子节点if (root->right) val1 += rob(root->right->left) + rob(root->right->right);      //不偷右孩子节点//不偷根节点int val2 = rob(root->left) + rob(root->right);memo[root] = max(val1, val2);       //记录数据return memo[root];}
};

思考二:递归法 + 动态规划。动态规划其实就是使用状态转移容器来记录状态的变化,这里可以使用一个长度为2的数组,记录当前节点偷与不偷所得到的的最大金钱。

下面以递归三部曲为框架,其中融合动规五部曲的内容来进行讲解思路

  • 确定递归函数的参数和返回值

这里我们要求一个节点 偷与不偷的两个状态所得到的金钱,那么返回值就是一个长度为2的数组。其实就是dp数组,dp[0]表示不偷当前节点的情况,dp[1]表示偷当前节点的情况。这些dp数组保存在系统栈中,递归返回时使用。

  • 确定终止条件

在遍历的过程中,如果遇到空节点的话,无论偷还是不偷都是0。这也是动态规划的初始化过程。

  • 确定遍历顺序

由于处理完节点后, 栈中保存的dp数组数据在返回时才使用,因此使用后序遍历处理二叉树。

通过递归左节点,得到左节点偷与不偷的金钱。

通过递归右节点,得到右节点偷与不偷的金钱。

  • 确定单层递归的逻辑

如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; 

如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);

最后当前节点的状态就是{val2, val1}; {不偷当前节点得到的最高金额,偷当前节点得到的最高金额}

这也是动态规划确定递推公式的过程。

  • 举例推导dp数组

以示例1为例,dp数组状态如下:(注意用后序遍历的方式推导)

最后头结点就是 取下标0 和 下标1的最大值就是偷得的最大金钱。 

代码:

class Solution {
public:// 长度为2的数组,0:不偷,1:偷vector<int> robTree(TreeNode* cur) {if (!cur)   return vector<int>{0, 0};vector<int> left = robTree(cur->left);          //左vector<int> right = robTree(cur->right);        //右int val1 = cur->val + left[0] + right[0];                       //偷当前节点int val2 = max(left[0], left[1]) + max(right[0], right[1]);    //不偷当前节点return vector<int>{val2, val1};}int rob(TreeNode* root) {vector<int> result = robTree(root);return max(result[0], result[1]);}
};

自我总结:

了解树形动态规划。感受递归+动态规划的设计逻辑:利用系统栈传递dp数组,相当于刷新dp数组

关于为什么树形结构,进行动态规划处理比进行暴力法处理节省时间以及为什么不会爆栈,先留下疑问,等理解清晰回头写思路。

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

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

相关文章

12-Linux部署Zookeeper集群

Linux部署Zookeeper集群 简介 ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的功能包括&#xff1a;配置维护、域名服务、分布式同步、组服务等。…

jmeter 压测数据库

当前版本&#xff1a; jmeter 5.6.3mysql 5.7.39 简介 JMeter 是一个开源的 Java 应用程序&#xff0c;主要用于进行性能测试和负载测试。它支持多种协议&#xff0c;包括但不限于 HTTP、HTTPS、FTP、JDBC 以及各种 Web Services。对于数据库的压力测试可以使用 JDBC 协议与数…

excel导入标准化

excel导入较导出还是复杂一些&#xff0c;一般分为三个步骤.市面上低代码平台可以将常用的操作固化&#xff0c;并且形成收益&#xff0c;这也是挺好的。我将我的一些总结分享到网上也是我自己乐意的。毕竟尊重技术的还是搞技术的自身&#xff0c;一般企业老板并不太关心技术代…

Spring中@import注解终极揭秘!

技术概念 它能干啥 Import注解在Spring框架中主要用于解决模块化和配置管理方面的技术问题&#xff0c;它可以帮助开发者实现以下几个目标&#xff1a; 模块化配置&#xff1a;在大型项目中&#xff0c;通常需要将配置信息分散到多个配置类中&#xff0c;以便更好地组织和管…

FPGA-DDS原理及实现

DDS(Direct Digital Synthesizer)即数字合成器,是一种新型的频率合成技术,具有相对带宽大,频率转换时间短、分辨率高和相位连续性好等优点。较容易实现频率、相位以及幅度的数控调制,广泛应用于通信领域。 相位累加器是由N位加法器与N位寄存器构成,每个时钟周期的上升沿,加法器…

【Qt】Qwidget的常见属性

目录 一、Qwidget核心属性 二、enable属性 三、geometry属性 四、 WindowFrame的影响 五、windowTitle属性 六、windowIcon属性 七、qrc文件管理资源 八、windowOpacity属性 九、cursor属性 十、font属性 十一、toolTip属性 十二、focusPolicy属性 十三、styleShe…

STM32FreeRTOS-事件组1(STM32Cube高效开发教程)

文章目录 一、事件组的原理和功能1、事件组与队列信号量特点2、事件组存储结构3、事件组运行原理 二、事件组部分函数1、xEventGroupCreate()创建事件组函数2、xEventGroupSetBits&#xff08;&#xff09;事件组置位函数3、xEventGroupSetBitsFromISR&#xff08;&#xff09;…

SQL技巧笔记(一):连续3人的连号问题—— LeetCode601.体育馆的人流量

SQL 技巧笔记 前言&#xff1a;我发现大数据招聘岗位上的应聘流程都是需要先进行笔试&#xff0c;其中占比很大的部分是SQL题目&#xff0c;经过一段时间的学习之后&#xff0c;今天开了一个力扣年会员&#xff0c;我觉得我很有必要去多练习笔试题目&#xff0c;这些题目是有技…

Linux - 进程概念

1、冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系&#xff1b; 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成&#xff1a; 输入单元&#xff1a;…

【JavaEE】_Spring MVC项目使用数组与集合传参

目录 1. 使用数组传参 1.2 传递单个参数 1.3 传递多个名称相同的参数 1.3.1 关于urlencode 2. 使用集合传参 1. 使用数组传参 创建一个Spring MVC项目&#xff0c;其中 .java文件内容如下&#xff1a; package com.example.demo.controller;import com.example.demo.Per…

自我对比: 通过不一致的解决视角更好地进行反思

一、写作动机&#xff1a; LLM 在自我评价时往往过于自信或随意性较大&#xff0c;提供的反馈固执或不一致&#xff0c;从而导致反思效果不佳。为了解决这个问题&#xff0c;作者提倡 "自我对比"&#xff1a; 它可以根据要求探索不同的解决角度&#xff0c;对比差异…

周边类-找厕所小程序源码

源码获取方式 1&#xff0c;搜一搜 万能工具箱合集 点击资料库 即可进去获取 找厕所小程序源码依赖于腾讯地图的一款源码&#xff0c;腾讯地图api免费申请&#xff0c;是一款免费又永久的不需要服务器的小程序&#xff0c;起个好名字蹭蹭蹭~ 搭建教程&#xff1a; 1、下载源码…

使用css的transition属性实现抽屉功能

需求 使用css手写一个抽屉&#xff0c;并且不能遮挡住原来的页面 效果&#xff1a;&#xff08;录的gif有点卡&#xff0c;实际情况很丝滑&#xff09; 实现代码&#xff1a; <template><div class"dashboard-container"><div class"mainBox&…

Java项目:36 springboot图书个性化推荐系统的设计与实现003

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 springboot003图书个性化推荐系统的设计与实现 管理员&#xff1a;首页、个人中心、学生管理、图书分类管理、图书信息管理、图书预约管理、退…

[element]element-ui框架下载

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601;…

基于Springboot的足球俱乐部管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的足球俱乐部管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍: 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff…

【Datawhale组队学习:Sora原理与技术实战】Attention和LLM

Attention Attention 注意力&#xff0c;从两个不同的主体开始。 论文&#xff1a;https://arxiv.org/pdf/1703.03906.pdf seq2seq代码仓&#xff1a;https://github.com/google/seq2seq 计算方法&#xff1a; 加性Attention&#xff0c;如&#xff08;Bahdanau attention&…

数据库-ODBC操作

承接Qt/C软件开发项目&#xff0c;高质量交付&#xff0c;灵活沟通&#xff0c;长期维护支持。需求所寻&#xff0c;技术正适&#xff0c;共创完美&#xff0c;欢迎私信联系&#xff01; 一、ODBC 数据源配置 打开ODBC数据源管理器&#xff1a; 在Windows搜索栏中键入“ODBC数…

PyTorch搭建LeNet神经网络

函数的参数 1、PyTorch Tensor的通道排序 [batch, channel, height, width] batch: 要处理的一批图像的个数 channel: 通道数&#xff08;一般是R G B 三个通道&#xff09; height: 图像的高度 width: 图像的宽度 2.Conv 2d 卷积层的参数 [in_channels, out_channels, ke…

Golang 开发实战day01 - Variable String Numeric

Golang 教程01 - Variable String Numeric 1. Go语言的重要性 Go语言&#xff0c;又称Golang&#xff0c;是一种由Google开发的静态编译型编程语言。它于2009年首次发布&#xff0c;并在短短几年内迅速流行起来。Go语言具有以下特点&#xff1a; 语法简单易学&#xff1a;Go…