算法训练 | 动态规划Part7 | 198.打家劫舍、213.打家劫舍II、337.打家劫舍III

目录

198.打家劫舍(线性)

动态规划法

213.打家劫舍II(环形)

动态规划法

337.打家劫舍III(二叉树)

动态规划法


198.打家劫舍(线性)

  • 题目链接:198. 打家劫舍 - 力扣(LeetCode)

  • 文章讲解:代码随想录

动态规划法
  • 解题思路

    • 当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。所以这里就更感觉到,当前状态和前面状态会有一种依赖关系,那么这种依赖关系都是动态规划的递推公式。

  • 解题步骤

    • 确定dp数组(dp table)以及下标的含义:dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[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房,(注意这里是考虑,并不是一定要偷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数组:

  • 代码注意

    • 初值设置

  • 代码一:动态规划

// 时间复杂度: O(n)
// 空间复杂度: O(n)
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());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];}
};

213.打家劫舍II(环形)

  • 题目链接:213. 打家劫舍 II - 力扣(LeetCode)

  • 文章讲解:代码随想录

动态规划法
  • 解题思路

      对于一个数组,成环的话主要有如下三种情况:注意这里用的是"考虑",例如情况三,虽然是考虑包含尾元素,但不一定要选尾部元素! 对于情况三,取nums[1] 和 nums[3]就是最大的。而情况二和情况三都包含了情况一了,所以只考虑情况二和情况三就可以了。

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

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

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

  • 解题步骤

    • 同打家劫舍1,只是抽离分情况

  • 代码一:动态规划

// 注意注释中的情况二情况三,以及把198.打家劫舍的代码抽离出来了
class Solution {
public: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); // 情况三return max(result1, result2);}// 198.打家劫舍的逻辑int robRange(vector<int>& nums, int start, int end) {if (end == start) 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 - 2] + nums[i], dp[i - 1]);}return dp[end];}
};

337.打家劫舍III(二叉树)

  • 题目链接:337. 打家劫舍 III - 力扣(LeetCode)

  • 文章讲解:代码随想录

动态规划法
  • 解题思路

    • 对于树的话,首先就要想到遍历方式,前中后序(深度优先搜索)还是层序遍历(广度优先搜索)。本题一定是要后序遍历,因为通过递归函数的返回值来做下一步计算。与198.打家劫舍,213.打家劫舍II一样,关键是要讨论当前节点抢还是不抢。如果抢了当前节点,两个孩子就不能动,如果没抢当前节点,就可以考虑抢左右孩子(注意这里说的是“考虑”)

    • 动态规划其实就是使用状态转移容器来记录状态的变化,这里可以使用一个长度为2的数组,记录当前节点偷与不偷所得到的的最大金钱。以二叉树递归三部曲为框架,其中融合动规五部曲。

  • 解题步骤

    • 确定递归函数的参数和返回值:要求一个节点偷与不偷的两个状态所得到的金钱,那么返回值就是一个长度为2的数组。所以dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。所以本题dp数组就是一个长度为2的数组!

    • 确定终止条件:在遍历的过程中,如果遇到空节点的话,很明显,无论偷还是不偷都是0,所以就返回。这也相当于dp数组的初始化。

    • 确定遍历顺序:首先明确的是使用后序遍历。 因为要通过递归函数的返回值来做下一步计算。通过递归左节点,得到左节点偷与不偷的金钱。通过递归右节点,得到右节点偷与不偷的金钱。

    • 确定单层递归的逻辑:如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (如果对下标含义不理解就再回顾一下dp数组的含义)如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);最后当前节点的状态就是{val2, val1}; 即:{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}

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

  • 代码一:x动态规划

// 时间复杂度:O(n),每个节点只遍历了一次
// 空间复杂度:O(log n),算上递推系统栈的空间
class Solution {
public:int rob(TreeNode* root) {vector<int> result = robTree(root);return max(result[0], result[1]);}// 长度为2的数组,0:不偷,1:偷vector<int> robTree(TreeNode* cur) {if (cur == NULL) return vector<int>{0, 0};vector<int> left = robTree(cur->left);vector<int> right = robTree(cur->right);// 偷cur,那么就不能偷左右节点。int val1 = cur->val + left[0] + right[0];// 不偷cur,那么可以偷也可以不偷左右节点,则取较大的情况int val2 = max(left[0], left[1]) + max(right[0], right[1]);return {val2, val1};}
};

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

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

相关文章

用友U9-UBF自定义报表-打印模板开发学习笔记

自定义报表、打印模板开发学习笔记 一、基础了解 1、UBF开发工具的了解 Ideconfig.xml配置 True&#xff1a;打印、报表设计模式 False&#xff1a;单据设计模式 2、开发环境试用 BE&#xff1a;实体项目 BF&#xff1a;操作项目 SV&#xff1a;服务项目 分析项目&am…

第5天:视图与模板进阶

第5天&#xff1a;视图与模板进阶 目标 掌握视图逻辑和模板渲染&#xff0c;包括不同类型的视图、自定义模板标签和过滤器&#xff0c;以及模板继承和包含的概念。 任务概览 学习函数视图和类视图的使用。编写自定义模板标签和过滤器。理解模板的继承和包含机制。 详细步骤…

NGINX_六 nginx 日志文件详解

六 nginx 日志文件详解 nginx 日志文件分为 **log_format** 和 **access_log** 两部分log_format 定义记录的格式&#xff0c;其语法格式为log_format 样式名称 样式详情配置文件中默认有log_format main $remote_addr - $remote_user [time_local] "req…

jQuery 基本操作

01-简介 jQuery 是一个功能丰富且广泛使用的 JavaScript 库&#xff0c;它简化了 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作。jQuery 通过其易用的 API&#xff0c;使复杂的 JavaScript 编程任务变得更加简单&#xff0c;并且兼容各种浏览器。 1、jQuery特点 简化 DOM …

【Mac】Pixelmator Pro for Mac(媲美PS的修图软件)软件介绍

软件介绍 Pixelmator Pro是一款功能强大的图像编辑软件&#xff0c;专为macOS平台设计。它结合了丰富的图像编辑功能和直观的用户界面&#xff0c;适合专业摄影师、设计师以及图像编辑爱好者。以下是Pixelmator Pro的一些主要特点和功能介绍&#xff1a; 功能特色 非破坏性编…

MSPM0G3507——创建新的.c.h文件

在项目处点击右键&#xff0c;再点击New File 再命名.c.h即可

JavaWeb——MySQL:DML对表数据的修改

2.DML对表数据的修改 2.1 修改表的数据 (1) 修改单行单列 SQL语句&#xff1a;update 表名 set 列名1数值1 where 列名2数值2&#xff1b; 将sql_student表姓名为吕小布的那行&#xff0c;性别设置为女&#xff1b; (2) 修改单行多列 SQL语句&#xff1a;update 表名 set 列…

交易者的意义是什么?

按照阿德勒的说法&#xff1a;人生的意义就是为社会创造价值&#xff0c;推动整个人类社会的发展进步。 我认同且秉持这种观点。 而在交易中&#xff0c;你是否直接或者间接为社会做贡献了呢&#xff1f;这个还真不好说。 但是做为职业交易者&#xff0c;你的存在价值&#…

Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的

文章目录 Elasticsearch聚合查询说明空值率查询DSL Elasticsearch聚合基础知识扩展Elasticsearch聚合概念Script 用法Elasticsearch聚合查询语法指标聚合&#xff08;Metric Aggregations&#xff09;桶聚合&#xff08;Bucket Aggregations&#xff09;矩阵聚合&#xff08;Ma…

IDEA插件开发,国际化处理

1.resources目录新增国际化资源文件 我项目默认英文&#xff0c;增加了一个zh中文的,en-英语 cn-中文 2.参数定义&#xff0c;中文需转为Unicode编码&#xff0c;推荐Unicode编码转换 - 站长工具 (chinaz.com) 3.新增类CodeChronoBundle继承AbstractBundle package com.codech…

牛顿迭代法(求解整数的近似平方根)

情景再现 面试官&#xff1a;给你一个整数怎样最快求解他的近似平方根&#xff1f; 小白&#xff1a;可以用while循环呀&#xff01; 面试官&#xff1a;有没有更好的方法&#xff1f; 小白&#xff1a;可以从这个数的左右两边开始迭代。 面试官&#xff1a;除了这个呢&#xf…

【从0实现React18】 (一) 项目初始化

Multi-repo 和 Mono-repo 由于需要同时管理多个包&#xff0c;如React、React-dom等&#xff0c;所以选择**Mono-repo** 选择使用pnpm-workspace搭建Mono-repo环境的原因 依赖安装快更规范 Pnpm初始化 npm install -g pnpm pnpm init配置pnpm-workspace.yml文件 pnpm-work…

ai assistant激活成功后,如何使用

ai assistant激活成功后&#xff0c;如图 ai assistant渠道&#xff1a;https://web.52shizhan.cn/activity/ai-assistant 在去年五月份的 Google I/O 2023 上&#xff0c;Google 为 Android Studio 推出了 Studio Bot 功能&#xff0c;使用了谷歌编码基础模型 Codey,Codey 是…

内容安全复习 4 - 深度生成模型

文章目录 概述经典算法自回归模型&#xff08;Autoregressive model&#xff09;变分自编码器&#xff08;VAE&#xff09;生成对抗网络&#xff08;GAN&#xff09;扩散模型&#xff08;Diffusion model&#xff09;总结 应用 概述 深度生成模型是一类使用深度学习技术构建的…

红队内网攻防渗透:内网渗透之内网对抗:横向移动篇入口差异切换上线IPC管道ATSC任务Impacket套件UI插件

红队内网攻防渗透 1. 内网横向移动1.1 横向移动入口知识点1.1.1、当前被控机处于域内还是域外1.1.1.1 在域内1.1.1.2 不在域内1.1.1.2.1 第一种方法提权到system权限1.1.1.2.2 第二种方法切换用户上线1.1.1.2.3 kerbrute枚举用户1.1.2、当前凭据为明文密码还是HASH1.2 横向移动…

flink学习-flink sql

动态表 在flink的数据处理中&#xff0c;数据流是源源不断的&#xff0c;是无界的&#xff0c;所以对于flink处理的数据表是一张动态表&#xff0c;所以对于动态表的查询也是持续的&#xff0c;每接收一条新数据会进行一次新的查询。 持续查询 因为数据在一直源源不动的到来…

跟TED演讲学英文:How language shapes the way we think by Lera Boroditsky

How language shapes the way we think Link: https://www.ted.com/talks/lera_boroditsky_how_language_shapes_the_way_we_think? Speaker: Lera Boroditsky Date: November 2017 文章目录 How language shapes the way we thinkIntroductionVocabularySummaryTranscriptA…

【单片机毕业设计选题24020】-全自动鱼缸的设计与应用

系统功能: &#xff08;1&#xff09;检测并控制鱼缸水温&#xff0c;水温低于22℃后开启加热&#xff0c;高于28℃后关闭加热。 &#xff08;2&#xff09;定时喂食&#xff0c;每天12点和0点喂食一次&#xff0c;步进电机开启后再关闭模拟喂食。 &#xff08;3&#xff09…

qt 简单实验 一个可以向左侧拖拽缩放的矩形

1.概要 向左拖拽矩形&#xff0c;和向右拖拽不同&#xff0c;向右拖拽是增加宽度&#xff0c;向左拖拽是增加宽度的同时还要向左移动x的坐标。 2.代码 2.1 resizablerectangleleft.h #ifndef RESIZABLERECTANGLELEFT_H #define RESIZABLERECTANGLELEFT_H #include <QWid…

【Matlab】-- BP反向传播算法

文章目录 文章目录 00 写在前面01 BP算法介绍02 基于Matlab的BP算法03 代码解释 00 写在前面 BP算法可以结合鲸鱼算法、飞蛾扑火算法、粒子群算法、灰狼算法、蝙蝠算法等等各种优化算法一起&#xff0c;进行回归预测或者分类预测。 01 BP算法介绍 BP&#xff08;Backpropag…