【动态规划】198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III

news2024/11/19 22:53:18

提示:努力生活,开心、快乐的一天

文章目录

  • 198. 打家劫舍
    • 💡解题思路
    • 🤔遇到的问题
    • 💻代码实现
    • 🎯题目总结
  • 213. 打家劫舍 II
    • 💡解题思路
    • 🤔遇到的问题
    • 💻代码实现
    • 🎯题目总结
  • 337. 打家劫舍 III
    • 💡解题思路
    • 🤔遇到的问题
    • 💻代码实现
    • 🎯题目总结
  • 🎈今日心得


198. 打家劫舍

题目链接:198. 打家劫舍

💡解题思路

  1. 当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了
    当前状态和前面状态会有一种依赖关系,那么这种依赖关系都是动规的递推公式。
  2. 动规五部曲:
  • 确定dp数组以及下标的含义: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] = max(dp[i - 2] + nums[i], dp[i - 1]);
  • dp数组如何初始化:dp[0] = nums[0];dp[1] = max(nums[0], nums[1])
  • 确定遍历顺序:dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历
  • 举例推导dp数组:按照递推公式推导一下做推导,如果发现结果不对,就把dp数组打印出来在这里插入图片描述

🤔遇到的问题

  1. 不需要像之前的背包问题一样,初始化dp数组
  2. 遍历从下标2开始遍历

💻代码实现

动态规划

var rob = function(nums) {
    let len = nums.length
    let dp = [nums[0], Math.max(nums[0], nums[1])]
    for (let i = 2; i < len; i++){
        dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i])
    }
    return dp[len-1]
};

🎯题目总结

当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了,是非常经典的DP题目


213. 打家劫舍 II

题目链接:213. 打家劫舍 II

💡解题思路

  1. 这道题目和198.打家劫舍 (opens new window)是差不多的,唯一区别就是成环了
    对于一个数组,成环的话主要有如下三种情况:
  • 情况一:考虑不包含首尾元素在这里插入图片描述
  • 情况二:考虑包含首元素,不包含尾元素在这里插入图片描述
  • 情况三:考虑包含尾元素,不包含首元素在这里插入图片描述
    里用的是"考虑",例如情况三,虽然是考虑包含尾元素,但不一定要选尾部元素! 对于情况三,取nums[1] 和 nums[3]就是最大的。
    而情况二 和 情况三 都包含了情况一了,所以只考虑情况二和情况三就可以了

🤔遇到的问题

  1. 调用原来的打家劫舍的代码,需要进行参数的修改

💻代码实现

动态规划

var rob = function (nums) {
    let len = nums.length
    if (len === 0) return 0
    if (len === 1) return nums[0]
    //不要尾 情况二
    let result2 = robRange(nums, 0, len - 2)
    //不要头 情况三
    let result1 = robRange(nums, 1, len - 1)
    return Math.max(result1, result2)

};
//与之前的没有环形的数组一样
const robRange = (nums, start, end) => {
    if (end === start) return nums[start]
    let len = nums.length
    let dp = new Array(len).fill(0)
    dp[start] = nums[start]
    dp[start+1] = Math.max(nums[start],nums[start+1])
    for (let i = start+2; i <= end; i++) {
        dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i])
    }
    return dp[end]
};

🎯题目总结

三种情况,情况一包含在情况二和情况三中。另外调用原来的方法需要进行改动,有数组的起始和结束为止的标识


337. 打家劫舍 III

题目链接:337. 打家劫舍 III

💡解题思路

  1. 首先就要想到遍历方式,前中后序(深度优先搜索)还是层序遍历(广度优先搜索)。
    本题一定是要后序遍历,因为通过递归函数的返回值来做下一步计算。
    如果抢了当前节点,两个孩子就不能动,如果没抢当前节点,就可以考虑抢左右孩子(注意这里说的是“考虑”)
  2. 动态规划其实就是使用状态转移容器来记录状态的变化,这里可以使用一个长度为2的数组,记录当前节点偷与不偷所得到的的最大金钱。
  3. 以递归三部曲为框架,其中融合动规五部曲的内容:
  • 确定递归函数的参数和返回值:这里我们要求一个节点 偷与不偷的两个状态所得到的金钱,那么返回值就是一个长度为2的数组,本题dp数组就是一个长度为2的数组!
  • 确定终止条件:在遍历的过程中,如果遇到空节点的话,很明显,无论偷还是不偷都是0
  • 确定遍历顺序:首先明确的是使用后序遍历。 因为要通过递归函数的返回值来做下一步计算。通过递归左节点,得到左节点偷与不偷的金钱。通过递归右节点,得到右节点偷与不偷的金钱。
  • 确定单层递归的逻辑:如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (如果对下标含义不理解就再回顾一下dp数组的含义);如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);最后当前节点的状态就是{val2, val1}; 即:{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}
  • 举例推导dp数组:以示例1为例,dp数组状态如下:(注意用后序遍历的方式推导)在这里插入图片描述

🤔遇到的问题

  1. 思路很难想到,基本是看着写出来的代码

💻代码实现

动态规划

const rob = root => {
    // 后序遍历函数
    const postOrder = node => {
        // 递归出口
        if (!node) return [0, 0];
        // 遍历左子树
        const left = postOrder(node.left);
        // 遍历右子树
        const right = postOrder(node.right);
        // 不偷当前节点,左右子节点都可以偷或不偷,取最大值
        const DoNot = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        // 偷当前节点,左右子节点只能不偷
        const Do = node.val + left[0] + right[0];
        // [不偷,偷]
        return [DoNot, Do];
    };
    const res = postOrder(root);
    // 返回最大值
    return Math.max(...res);
};

🎯题目总结

只不过平时我们习惯了在一维数组或者二维数组上推导公式,一下子换成了树,就需要对树的遍历方式足够了解!

🎈今日心得

打家劫舍还不错,思路捋清楚以后,可以举一反三啦,打家劫舍III是真的难啊

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

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

相关文章

postman发送POST请求,模拟请求头界面的响应信息

postman发送POST请求 示例&#xff1a;微信公众平台创建用户标签接口&#xff0c;业务操作如下&#xff1a; 1、打开微信公众平台&#xff0c;微信扫码登录&#xff1a;https://mp.weixin.qq.com/debug/cgi-bin/sandbox?tsandbox/login 同时&#xff0c;我也为大家准备了一份…

求二叉树节点的个数——后序遍历

之前我们已经学习了二叉树前中后序的遍历&#xff0c;在次基础上我们利用遍历来求二叉树的节点个数 利用变量来计数&#xff1a; int BinaryTreeSize(BTNode* root) {int size 0;if (root NULL){return 0;}else{size;}BinaryTreeSize(root->left);BinaryTreeSize(root-&…

Spring5应用之事务属性

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Spring5应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言事务…

指针拔尖(2)(巩固提高,全网最牛,包会,看不懂带电脑来找我)

文章目录 前言变量的声明 一、函数指针二、函数指针数组三、指向函数指针数组的指针四、 回调函数总结 前言 提示&#xff1a;本章是指针拔尖系列的终章&#xff0c;有四大知识点。 一、函数指针 二、函数指针数组 三、指向函数指针数组的指针 四、回调函数 但学习这些知识点我…

【STM32单片机】防盗报警器设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使用按键、动态数码管、蜂鸣器、指示灯、热释电人体红外传感器等。 主要功能&#xff1a; 系统运行后&#xff0c;默认处于布防状态&#xff0c;D1指示灯…

Netty深入浅出Java网络编程学习笔记(三) 优化篇

目录 五、优化 1、拓展序列化算法 序列化接口 枚举实现类 修改原编解码器 2、参数调优 CONNECT_TIMEOUT_MILLIS 使用 源码分析 SO_BACKLOG 三次握手与连接队列 作用 默认值 TCP_NODELAY SO_SNDBUF & SO_RCVBUF ALLOCATOR 使用 ByteBufAllocator类型 RCVBUF_ALLOCATOR 3、RP…

2023.10.11

#include <iostream>using namespace std;class Sofa{ private:int price;int* size; public://无参构造Sofa(){}//有参构造Sofa(int p,int size):price(p),size(new int(size)){}//析构~Sofa(){delete size;}//拷贝构造Sofa(Sofa &other):price(other.price),size(n…

TensorFlow入门(二十、损失函数)

损失函数 损失函数用真实值与预测值的距离指导模型的收敛方向,是网络学习质量的关键。不管是什么样的网络结构,如果使用的损失函数不正确,最终训练出的模型一定是不正确的。常见的两类损失函数为:①均值平方差②交叉熵 均值平方差 均值平方差(Mean Squared Error,MSE),也称&qu…

[计算机网络基础]物理层详解

首先说明,基本的概述我还没写完,那部分虽然简单但是感觉要照顾到很多概念..... 以及本系列博客使用点模型并非iso模型,也并非tcp/IP模型,而是我们俗称的教学模型 也就是:物理层,数据链路层,网络层,传输层,应用层这五个,整个模型大多数是在教学中使用的,现实中基本不会这样子划…

spring容器ioc和di

spring ioc 容器的创建 BeanFactory 接口提供了一种高级配置机制&#xff0c;能够管理任何类型的对象&#xff0c;它是SpringIoC容器标准化超接口&#xff01; ApplicationContext 是 BeanFactory 的子接口。它扩展了以下功能&#xff1a; 更容易与 Spring 的 AOP 功能集成消…

K8S云计算系列-(3)

K8S Kubeadm案例实战 Kubeadm 是一个K8S部署工具&#xff0c;它提供了kubeadm init 以及 kubeadm join 这两个命令来快速创建kubernetes集群。 Kubeadm 通过执行必要的操作来启动和运行一个最小可用的集群。它故意被设计为只关心启动集群&#xff0c;而不是之前的节点准备工作…

echarts仪表盘vue

<div class"ybptx" ref"btryzb"></div>mounted() {this.getBtData();},getBtData() {var chart this.$echarts.init(this.$refs.btryzb);var data_czzf 88;var option {series: [{name: 内层数据刻度,type: gauge,radius: 80%,min: 0,max: 1…

Selenium+Pytest自动化测试框架

前言 selenium自动化 pytest测试框架 本章你需要 一定的python基础——至少明白类与对象&#xff0c;封装继承 一定的selenium基础——本篇不讲selenium&#xff0c;不会的可以自己去看selenium中文翻译网 测试框架简介 测试框架有什么优点呢&#xff1a; 代码复用率高&…

【安全】linux audit审计使用入门

文章目录 1 audit简介2 auditctl的使用2 audit配置和规则3 工作原理4 audit接口调用4.1 获取和修改配置4.2 获取和修改规则4.3 获取审计日志 5 audit存在的问题5.1 内核版本5.2 审计日志过多造成的缓存队列和磁盘问题5.2 容器环境下同一个命令的日志存在差异 6 参考文档 1 audi…

【gmail注册教程】手把手教你注册Google邮箱账号

手把手教你注册Google邮箱账号 写在前面&#xff1a; 要注意&#xff0c;注册Google邮箱必须要确保自己能够 科学上网&#xff0c;如果暂时做不到&#xff0c;请先进行相关学习。使用的手机号是大陆&#xff08;86&#xff09;的。 在保证自己能够科学上网后&#xff0c;在浏…

[硬件基础]-双稳态多谐振荡器配置

双稳态多谐振荡器配置 文章目录 双稳态多谐振荡器配置1、概述2、双稳态多谐振荡器的内部运行原理 在上一篇文章中&#xff0c;我们深入了解了555定时器在单稳态模式下的内部工作原理。 如果您已经理解了上一篇文章&#xff0c;那么本文对您来说将会非常简单。 我们将研究 555 定…

C++ - 智能指针 - auto_ptr - unique_ptr - std::shared_ptr - weak_ptr

前言 C当中的内存管理机制需要我们自己来进行控制&#xff0c;比如 在堆上 new 了一块空间&#xff0c;那么当这块空间不需要再使用的时候。我们需要手动 delete 掉这块空间&#xff0c;我们不可能每一次都会记得&#xff0c;而且在很大的项目程序当中&#xff0c;造成内存泄漏…

【合集】Java进阶——Java深入学习的笔记汇总 JVM底层、多线程、类加载 ...

前言 spring作为主流的 Java Web 开发的开源框架&#xff0c;是Java 世界最为成功的框架&#xff0c;持续不断深入认识spring框架是Java程序员不变的追求&#xff1b;而spring的底层其实就是Java&#xff0c;因此&#xff0c;深入学习Spring和深入学习Java是硬币的正反面&…

[代码随想录]二叉树篇

文章目录 1. 二叉树之层序遍历1.1 144-二叉树的前序遍历1.2 94-二叉树的中序遍历1.3 145-二叉树的后序遍历1.4 102-二叉树的层序遍历1.5 107-二叉树的层序遍历II1.6 199-二叉树的右视图1.7* 637-二叉树的层平均值1.8* 429-N叉树的层序遍历1.9 515-在每个树行中找最大值1.10* 11…

【算法挨揍日记】day14——724. 寻找数组的中心下标、238. 除自身以外数组的乘积

724. 寻找数组的中心下标 724. 寻找数组的中心下标 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的和。 如果中心下标位于数组最左端&#…