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

news2024/11/18 22:51:59

198.打家劫舍

力扣题目链接/文章讲解

视频讲解

动态规划五部曲!

1、定义 dp 数组下标及值的含义

dp[i]:从下标 0 到 i 的房屋里偷,值表示从下标 0 到 i 的房屋里面偷最多可以偷到金额为 dp[i]

2、确定递推公式

要求 dp[i],需考虑从下标 0 到 i 的房屋里应该怎么偷。偷窃方案可以分成两类:该方案偷了房屋 i 和该方案没偷房屋 i

偷了房屋 i:则此时房屋 i - 1 不能偷,偷了 i 之后剩下只能在房屋 0 到 i - 2 里面尽可能多偷点,即该方案最多可以偷到的金额为 nums[i] + dp[i - 2]

没偷房屋 i:则此时相当于在房屋 0 到 i - 1 里面尽可能多偷点,即该方案最多可以偷到的金额为 dp[i - 1]

下标 0 到 i 的房屋里面偷最多可以偷到金额 dp[i] 为两类方案中的最大值,即递推公式为:dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])

3、dp 数组初始化

根据递推公式可以看出,dp[i] 是通过 dp[i - 1] 和 dp[i - 2] 推导出来,因此应该初始化 dp[0] 和 dp[1]

dp[0]:从房间 0 里面最多可以偷到的金额,就是房间 0 里面有的金额,dp[0] = nums[0]

dp[1]:从房间 0 到 1 里面最多可以偷到的金额,就是房间 0 和 1 里面的金额的最大值,dp[0] = max(nums[0], nums[1])

其他位置随意初始化,反正会被覆盖 

4、确定遍历顺序

当前 dp 值是由前两个 dp 值推导出来的,那么一定是从前到后遍历,保证前两个 dp 值是已被更新的正确值

5、打印 dp 数组验证

代码如下

class Solution {
public:
    int rob(vector<int>& nums) {

        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];

        // 确定dp数组下标及值含义
        // dp[i]:从下标0-i的房间偷,最多能偷到的金额为dp[i]
        vector<int> dp(nums.size());

        // 递推公式:考虑偷房间i和不偷房间i两种偷窃方案,dp[i] = max(nums[i]+dp[i-2], dp[i-1])
        
        // 初始化dp[0]和dp[1]
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]); 
        
        for (int i = 2;i < nums.size(); ++i) {  // 从左向右遍历,dp[0]和dp[1]已被初始化了
            dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);
        }

        // 打印dp数组验证略

        return dp.back();
    }
};

213.打家劫舍II 

力扣题目链接/文章讲解

视频讲解

本题和 198.打家劫舍 的唯一区别就是房屋成环了

成环意味着,偷了第一个房间就不能偷最后一个房间,偷了最后一个房间就不能偷第一个房间

我们分两种考虑:

第一种仅考虑除最后一个房间之外的房间,这样能够保证首尾不会都被偷

第二种仅考虑除第一个房间之外的房间,这样能够保证首尾不会都被偷

这两种都是仅考虑红框部分,则每种考虑的处理方式和 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(vector<int>(nums.begin(), nums.end() - 1)); // 仅考虑除最后一个房间之外的房间
        int result2 = robRange(vector<int>(nums.begin() + 1, nums.end())); // 仅考虑除第一个房间之外的房间
        return max(result1, result2);
    }
    int robRange(const vector<int>& nums) {   // 打家劫舍I的代码

        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];

        // 确定dp数组下标及值含义
        // dp[i]:从下标0-i的房间偷,最多能偷到的金额为dp[i]
        vector<int> dp(nums.size());

        // 递推公式:考虑偷房间i和不偷房间i两种偷窃方案,dp[i] = max(nums[i]+dp[i-2], dp[i-1])
        
        // 初始化dp[0]和dp[1]
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]); 
        
        for (int i = 2;i < nums.size(); ++i) {  // 从左向右遍历,dp[0]和dp[1]已被初始化了
            dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);
        }

        // 打印dp数组验证略

        return dp.back();
    }
};

337.打家劫舍III 

力扣题目链接/文章讲解

视频讲解

本题和树有关, 我们做树的题目就是递归三部曲或者回溯

本题要用递归三部曲,结合动态规划的思想

复习一下递归三部曲

递归把握一个关键点:确定这个递归调用能干什么事

递归三部曲(每一步都考虑一下那个关键点)

  1. 确定递归的参数和返回值
  2. 确定终止条件
  3. 确定单层递归的逻辑(往往想到能不能利用本身递归函数解决子问题) 

我们就按照递归三部曲的思路,一步一步来做这道题

首先明确递归函数功能:传入一棵树,返回在这棵树上能够偷到的最大金额

因为在一棵树上偷,有两种方案:要偷根节点的方案,及不偷根节点的方案,是否偷某棵子树的根节点与我们决策某棵子树的父节点应该怎么偷息息相关,于是我们分开考虑

因此我们递归函数功能优化为:传入一棵树,返回偷了该树根节点所能偷到的最大金额及不偷该树根节点所能偷到的最大金额

然后递归三部曲

1、 确定递归的参数和返回值

传入一棵树表示等待被偷的树,返回一个数组,数组存放的是偷了该树根节点所能偷到的最大金额及不偷该树根节点所能偷到的最大金额

vector<int> robTree(TreeNode* cur)
// 返回数组vec
// vec[0]存放的是不偷树的根节点所能偷到的最大金额
// vec[1]存放的是偷了树的根节点所能偷到的最大金额

2、 确定递归终止条件

在遍历的过程中,如果遇到空节点的话,很明显,无论偷还是不偷都是0,所以就返回

if (cur == NULL) return vector<int>{0, 0};

3、 确定单层递归逻辑

单层递归是需要我们分别返回偷了该树根节点及不偷该树根节点两种方案所能偷到的最大金额

偷该树根节点所能偷到的最大金额:为根节点金额、不偷左子树根节点所能偷到的最大金额、不偷右子树根节点所能偷到的最大金额之和

不偷该树根节点所能偷到的最大金额:为偷左子树根节点所能偷到的最大金额、偷右子树根节点所能偷到的最大金额之和

偷或者不偷其子树根节点所能偷到的最大金额能够通过递归调用本身实现 

// 偷或者不偷其子树根节点所能偷到的最大金额能够通过递归调用本身
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]);

// 返回数组位置0代表不偷,位置1代表偷
return {val2, val1};

整体代码如下

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};
    }
};

回顾总结 

最后一道题树形 dp 挺有难度

前两道就是常规动态规划题,定义好 dp,推出递推公式就很简单了

总的来说比背包问题简单太多 

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

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

相关文章

松弛去噪:无源数据的无监督域自适应眼底图像分割

文章目录 Denoising for Relaxing: Unsupervised Domain Adaptive Fundus Image Segmentation Without Source Data摘要本文方法Pseudo Labeling with Class-Dependent ThresholdsLabel Self-correction Towards Effective AdaptationClass-Conditional Label Error Estimation…

Qt复制文件到C盘目录超级管理员权限和避免VirtualStore功能

本以为复制文件是个很简单的事情&#xff0c;没想到居然需要超级管理员权限。 网上一搜有好多教程&#xff0c;例如这个&#xff1a; 给Qt程序添加管理员权限总结&#xff08;一定有你没见过的方式&#xff09;_qt管理员权限_百里杨的博客-CSDN博客当我们写了一个Qt程序&…

联想台式机第一次激活提示“请连接Internet进行设置”

一、问题描述 近期给客户新采购了若干台Think系列的联想服务器&#xff08;台式机&#xff09;&#xff0c;在开机初始化时&#xff0c;选择了语言、键盘模式&#xff0c;然后点击“下一步”&#xff0c;页面提示“请连接Internet进行设置”。 此时右下角的“下一步”是灰色的…

民宿小程序源码搭建 酒店预订小程序源码 完整前后端+安装搭建教程

分享一个民宿小程序源码搭建酒店预订小程序源码&#xff0c;含完整代码程序包和详细的安装搭建教程。 系统为多用户&#xff0c;可以多商家入驻收入驻费用运营&#xff0c;可自用搭建民宿酒店小程序&#xff0c;在线订房管理。 小程序源码下载地址&#xff1a;春哥技术博客获取…

深耕全屋智能场景 鸿雁发布两款iHousePad智慧交互屏新品

作为全屋智能中最核心的应用&#xff0c;智慧屏一直是入口级的产品&#xff0c;在全屋智能场景中起着重要的作用&#xff0c;智慧屏体验的好坏直接关系到全屋智能的交互体验和落地应用。 作为全屋智能赛道早期布局者和重要推动者&#xff0c;鸿雁一直在推动传统开关面板到智能…

【第六章:总线】

目录 知识框架No.0 引言No.1 总线概述一、基本概念二、总线的分类及经典结构1、按照数据传输格式2、按照总线功能(连接的部件)3、按照时序控制方式 三、性能指标1.总线的传输周期(总线周期)2.总线时钟周期3.总线的工作频率4.总线的时钟频率5.总线宽度6.总线带宽7.总线复用8.信号…

spring-data 一统江湖,玩转多种数据源

1、起因 因为要在项目中同时访问redis&#xff0c;mongo和mysql三种数据库&#xff0c;而且因为偏向spring-data&#xff0c;所以都使用了spring-data 在使用的过程中如果不做配置发现会有冲突&#xff0c;这篇文章也是解决这个问题&#xff0c;避免以后遇到同样的问题不知所…

【SAM系列】CAN SAM COUNT ANYTHING? AN EMPIRICAL STUDY ON SAM COUNTING

论文链接&#xff1a;https://arxiv.org/abs/2304.10817 代码链接&#xff1a;https://github.com/vision-intelligence-and-robots-group/count-anything 目的 探索SAM在few-shot setting的object counting的能力。 结论 它目前落后于最先进的few-shot object counting方法…

出门没带本子记的单词|10:20~10:40

susceptible adj 易受影响的 unify v 统一 auditory adj 听觉的 / ˈɔːdətɔːri / combat v 与...搏斗、防止 comfort n 舒适 constrain v 约束、迫使 fringe …

Swift 周报 第二十九期

文章目录 前言新闻和社区担心泄密&#xff01;外媒&#xff1a;苹果公司限制员工使用ChatGPT苹果公司大幅削减其MR头显销售预期&#xff0c;不足百万台 提案通过的提案正在审查的提案 Swift 论坛1、讨论 SwiftUI 图表、超大数据集和图表叠加2、讨论带有线程安全属性包装器的可发…

【SpringBoot知识点预备】| Xml 和 JavaConfig

目录 一&#xff1a;Xml 和 JavaConfig 1. JavaConfig 2. ImportResource注解 3. PropertyResource注解 一&#xff1a;Xml 和 JavaConfig 1. JavaConfig &#xff08;1&#xff09;为什么要使用 Spring Boot&#xff1f; ①因为Spring、SpringMVC 的使用需要大量的配置文…

【Java EE】Springboot

Springboot Springboot 核心功能SpringBoot的相关好处 Springboot 核心功能 1、 可独立运行的Spring项目&#xff1a;Spring Boot可以以jar包的形式独立运行。 2、 内嵌的Servlet容器&#xff1a;Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow&#xff0c;无须以war包形…

python cuda torch验证是否成功安装,版本是否匹配

1 、首先查看自己的显卡型号 根据nvcc-smi查到自己的显卡型号,如下图所示。 本人的电脑显卡型号为:GeForce GT 730 2、查看显卡算力 可以通过以下链接查找 http://www.5ityx.com/cate100/155907.html 可以看到我的显卡算力是3.5 备注:你的显卡计算力必须保证在3.5以上。如…

Kali-linux破解纯文本密码工具mimikatz

mimikatz是一款强大的系统密码破解获取工具。该工具有段时间是作为一个独立程序运行。现在已被添加到Metasploit框架中&#xff0c;并作为一个可加载的Meterpreter模块。当成功的获取到一个远程会话时&#xff0c;使用mimikatz工具可以很快的恢复密码。本节将介绍使用mimikatz工…

使用Python获取公众号下所有的文章

我比较喜欢看公众号&#xff0c;有时遇到一个感兴趣的公众号时&#xff0c;都会感觉相逢恨晚&#xff0c;想一口气看完所有历史文章。本文主要介绍了使用Python获取公众号下所有的文章&#xff0c;感兴趣的可以了解一下 导出公众号所有文章 随着互联网的不断发展&#xff0c;网…

【源码篇】基于SpringBoot+Jsp的日记记录系统

1、项目介绍 基于SpringBootJsp的日记记录系统所有功能均对用户开放&#xff0c;只有用户角色。 是一款面向用户的系统&#xff0c;用户可以自己注册账号进行登录&#xff0c;管理自己的信息(个人中心)、自由添加日记分类、发布日记来记录自己所遇到有趣的人和事、也可以发表…

BiFormer 实验记录

代码来自文中地址 目录 一、前向传播过程 1、Path Embedding 2、BiFormer Block BRA模块 网络结构 一、前向传播过程 1、Path Embedding 见网络结构部分&#xff0c;4倍下采样 2、BiFormer Block 对应 x x self.pos_embed(x) 对应 x x self.drop_path(self.attn(…

【5.22】七、移动App测试

目录 7.1 移动App测试概述 1. 移动App特性 2. 移动App测试与传统软件测试的区别 7.2 移动App测试要点 7.2.1 UI测试 7.2.2 功能测试 7.2.3 专项测试 7.2.4 性能测试 7.3 移动App测试流程 第三方测试平台 7.4 移动App测试工具 7.1 移动App测试概述 移动App&#xff…

就业内推 | 应届生专场,有华为、思科认证优先,六险一金

01 金科 &#x1f537;招聘岗位&#xff1a;网络工程师 &#x1f537;职责描述&#xff1a; 1、为银行、企业客户提供技术服务&#xff08;包括驻场支持和现场技术支持&#xff09;&#xff1b; 2、驻客户现场配合客户完成思科、华三、华为主流网络设备的配置、管理&#xff1…

基于C++的类UNIX文件系统

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 一、题目要求 使用一个普通的大文件&#xff08;如 c:\myDisk.img &#xff0c;称之为一级文件&#xff09;模拟 UNIX V6的一个文件卷&#xff0c;一个文件卷实际上就是一张逻辑磁盘&#xff0c;磁盘中存储的信息以块为单位。…