【代码随想录day37】【C++复健】198.打家劫舍;213.打家劫舍II ;337.打家劫舍III

198.打家劫舍

本题别的地方都写出来了,不过在最后写的时候我没想明白dp[n-2]有没有可能比dp[n-1]大,写了个max(dp[n-1],dp[n-2])。但其实这个问题很简单,因为在dp数组里面dp[i]里取max的时候有一项就是dp[i-1],所以一定是大于等于的。
class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n);
        dp[0] = nums[0];
        if(n <= 1){
            return dp[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[n-1];
    }
};

213.打家劫舍II

本题老毛病又犯了,这两个dp数组可以用一个函数进行复用,然后只要输入不同的下标即可,但是我却自己实现了这两个dp数组,在传值和合法性判断上,写起来麻烦不少,不过好在能正常执行。

还有一个问题是不知道max函数只能比较两个值,也不知道不能传两个迭代器,如果要比较三个数就只能调用两次max函数了。

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        if(n <= 1){
            return nums[0];
        }
        vector<int> dp1(n-1);
        dp1[0] = nums[0];
        if(n <=2){
            return max(nums[0], nums[1]);
        }
        if(n <= 3){
            return max(nums[0], max(nums[1], nums[2]));
        }
        dp1[1] = max(nums[0], nums[1]);
        vector<int> dp2(n-1);
        dp2[0] = nums[1];
        dp2[1] = max(nums[1], nums[2]);
        for(int i=2; i<n-1; i++){
            dp1[i] = max(dp1[i-1], dp1[i-2] + nums[i]);
        }
        for(int i=3; i<n; i++){
            dp2[i-1] = max(dp2[i-2], dp2[i-3] + nums[i]);
        }
        return max(dp1[n-2], dp2[n-2]);
    }
};

337.打家劫舍III

这个打家劫舍的题也是二周目了,上一周目印象很深,所以本来以为能写对的,但还是在dp数组上面写错了。问题就出在了第二个向量,也就是不打劫根节点的时候的更新方式上面:

我写的更新代码如下:
int second = max(right[0] + left[0], right[1] + left[1]);

但实际正确的应该是:
int second = max(left[0], left[1]) + max(right[0], right[1]);

这两句之间差在哪了呢?差就差在,上面这个写法,左子树和右子树只能同时选择偷这个节点或不偷这个节点,但实际这个逻辑是不对的,当我选择不偷根节点的时候,左子树和右子树的偷或者不偷之间是完全没有关系的,它们之间应该是独立的关系,否则就会漏掉一些情况。

而底下这个写法才保证了左右之间的相互独立的关系。

此外再啰嗦一点,为什么这个时候,前后节点需要进行大小的比较?这里的比较有点类似上一道题里面最后的比较,因为0号位和1号位实际上取值的区间是不同的,所以它们之间的大小也没有绝对关系,当然要进行比较来取最大。而1里面因为存在包含关系,所以不比较也可以。

还有就是vector<int>,如果我想要定义一个vector,里面的0号位和1号位是两个0,那应该用大括号,而非小括号,小括号的vector<int> (0,0) 代表的是长度和初始值都为0的一个vector。

class Solution {
public:
    int rob(TreeNode* root) {
        if(!root){
            return 0;
        }
        vector<int> result = midgap(root);
        return max(result[0], result[1]);
    }
    vector<int> midgap(TreeNode* root){
        if(!root){
            return vector<int> {0,0};
        }
        vector<int> left = midgap(root->left);
        vector<int> right = midgap(root->right);
        int first = left[1] + right[1] + root->val;
        int second = max(left[0], left[1]) + max(right[0], right[1]);
        return vector<int> {first, second};
    }
};

最后附上GPT对于为什么三需要比较而一不需要的解释:

打家劫舍 III 中需要比较的原因:

打家劫舍 III 中,我们用一个二维的状态来表示每个节点的选择。对于每个节点,我们有两个可能的选择:

  1. 不偷当前节点,这意味着我们可以选择左右子树的最大收益,max(left[0], left[1]) + max(right[0], right[1])
  2. 偷当前节点,这时我们必须计算左右子树的“不偷”收益,即 left[0] + right[0] + root->val

由于 左右子树的选择是独立的,它们的最大值并不直接包含或依赖对方。因此,在 打家劫舍 III 中,我们需要分别比较左右子树中“偷或不偷”的收益,以便找到最优的方案。

打家劫舍 I 中的大小比较:

打家劫舍 I 中,问题是一维的,我们用 dp[i] 表示抢劫到第 i 个房子时的最大金额。状态转移方程是:

dp[i] = max(dp[i-1], dp[i-2] + nums[i]);

这里的比较,实际上是一个 互斥 的选择,因为如果你选择了抢劫第 i 个房子,你就不能抢劫第 i-1 个房子,反之亦然。这就是为什么我们需要进行比较来找出最大的收益,因为我们有两种互斥的选择(偷或不偷)。

为什么 0号位和1号位取值区间不同,且需要比较

打家劫舍 III 中,0号位1号位 表示两种不同的状态:

  • 0号位 表示“不偷当前节点”,它的值是左右子树的最大值(不包括当前节点的值)。
  • 1号位 表示“偷当前节点”,它的值是当前节点的值加上左右子树不偷的最大值。

这两个状态的取值区间是不同的,因为它们分别代表了两种完全不同的策略:

  • 不偷当前节点:你可以选择偷或者不偷左子树和右子树。
  • 偷当前节点:你只能选择不偷左子树和右子树。

这两个状态之间并没有包含关系,所以必须进行比较,以确定偷或不偷哪个更有利。

为什么在打家劫舍 I 中不需要比较

打家劫舍 I 中,状态转移是基于两个状态(抢劫当前房子或不抢劫),它们之间并没有独立性或者包含关系。直接用 max(dp[i-1], dp[i-2] + nums[i]) 就可以得到最大值。这是因为 dp[i-1]dp[i-2] 表示相邻房子的状态选择,两者的选择是互斥的,并且不需要考虑它们之间的包含关系。

结论:

  • 打家劫舍 III 中,需要比较左右子树的“偷或不偷”最大值,因为左右子树的选择是独立的,没有包含关系,必须独立选择。
  • 打家劫舍 I 中,不需要额外比较,因为每个房子的选择是基于前一个房子的状态,两个选择是互斥的,不需要考虑包含关系。

所以,你的理解是对的,打家劫舍 III 中的大小比较类似于 打家劫舍 I 中的比较,但原因不同,主要是 独立选择互斥选择 的问题。

希望这次解释能帮你更好地理解这个问题!如果有其他问题,随时问我。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于LiteFlow的风控系统指标版本控制

个人博客&#xff1a;无奈何杨&#xff08;wnhyang&#xff09; 个人语雀&#xff1a;wnhyang 共享语雀&#xff1a;在线知识共享 Github&#xff1a;wnhyang - Overview 更新日志 最近关于https://github.com/wnhyang/coolGuard此项目更新了如下内容&#xff1a;https://g…

Spring:AOP切入点表达式

对于AOP中切入点表达式&#xff0c;我们总共会学习三个内容&#xff0c;分别是语法格式、通配符和书写技巧。 语法格式 首先我们先要明确两个概念: 切入点:要进行增强的方法切入点表达式:要进行增强的方法的描述方式 对于切入点的描述&#xff0c;我们其实是有两中方式的&a…

docker搭建私有的仓库

docker搭建私有仓库 一、为什么要搭建私有的仓库&#xff1f; 因为在国内&#xff0c;访问&#xff1a;https://hub.docker.com/ 会出现无法访问页面。。。。&#xff08;已经使用了魔法&#xff09; 当然现在也有一些国内的镜像管理网站&#xff0c;比如网易云镜像服务、Dao…

大白话讲Promise(最详细)

学前端的大家都知道promise是重中之重&#xff0c;也是面试的必考项。但是刚接触promise我一直很晕头晕脑的&#xff0c;搜集文章前看后看基本都是讲解promise的状态它的方法就没有再深入了&#xff0c;以至于面试时候面试官一旦往深问我就懵了。所以今天我们就详细的说一下pro…

【笔记】自动驾驶预测与决策规划_Part7_数据驱动的预测方法

文章目录 0. 前言1. 多模态传感器的编码方式1.1 栅格化表示1.2 向量化表示 Vectornet1.3 基于点云或者多模态输入的预测1.4 基于Transformer的方法 2. 网络输出的表达形式2.1 多模态轨迹回归2.2 轨迹分类2.3 轨迹回归轨迹分类2.4 目标点预测 3.场景级别的预测和决策3.1 论文&am…

回溯法经典难题解析

本文将通过几个经典的回溯问题&#xff0c;展示回溯算法的应用及其在解决问题时的核心思想和技巧。这些问题包括全排列、全排列II、N皇后以及数独问题&#xff0c;本文将分别介绍每个问题的思路与实现。 46. 全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有…

无线图传下的低延迟视频传输播放技术探讨

技术背景 无线图传技术即无线图像传输技术&#xff0c;是指不用布线&#xff08;线缆&#xff09;利用无线电波来传输图像数据的技术。 一、工作原理 无线图传技术主要涉及图像采集、编码、调制、发射、接收、解调、解码和图像显示等环节。 图像采集&#xff1a;通过摄像头…

软件测试面试之常规问题

1.描述一下测试过程 类似题目:测试的生命周期 思路:这是一个“范围”很大的题目&#xff0c;而且回答时间一般在3分钟之内&#xff0c;不可能非常详细的描述整个过程&#xff0c;因此答题的思路要从整体结构入手&#xff0c;不要过细。为了保证答案的准确性&#xff0c;可以引…

C++从零到满绩——类和对象(中)

目录 1>>前言 2>>构造函数&#xff08;我称之为初始化函数&#xff09; 3>>析构函数&#xff08;我称之为销毁函数&#xff09; 4>>拷贝构造函数&#xff08;我称之为复制函数&#xff09; 5>>运算符重载 5.2>>赋值运算符重载 ​编辑…

内网渗透横向移动1

1.信息收集 &#xff08;1&#xff09;判断域控 shell net time /domain shell ping OWA2010CN-God.god.org &#xff08;2&#xff09;主机探测 浏览探测->网络探测 主机列表显示&#xff1a; &#xff08;3&#xff09;域用户收集&#xff1a; shell net user /domain…

Edify 3D: Scalable High-Quality 3D Asset Generation 论文解读

目录 一、概述 二、相关工作 1、三维资产生成 2、多视图下的三维重建 3、纹理和材质生成 三、Edify 3D 1、文本生成多视角图像的扩散模型 2、文本和多视角图像生成法线图像的ControlNet 3、重建与渲染模型 4、多视角高分辨率RGB图像生成 四、训练 1、训练过程 2、…

微软正在测试 Windows 11 对第三方密钥的支持

微软目前正在测试 WebAuthn API 更新&#xff0c;该更新增加了对使用第三方密钥提供商进行 Windows 11 无密码身份验证的支持。 密钥使用生物特征认证&#xff0c;例如指纹和面部识别&#xff0c;提供比传统密码更安全、更方便的替代方案&#xff0c;从而显著降低数据泄露风险…

词云图大师(WordCloudMaster): 探索创意无限的词云世界!

在信息化时代&#xff0c;如何以一种新颖且富有创意的方式表达数据、文字或想法&#xff1f;答案是词云图&#xff01;而词云图大师(WordCloudMaster)&#xff0c;正是您的绝佳选择。 无论是个人创意项目&#xff0c;还是专业工作中的数据可视化&#xff0c;词云图大师都能以强…

pycharm使用debug的时候遇到断点不停的问题

1.首先尝试在程序最开头打断点&#xff0c;检查是否能停下&#xff0c;如果可以&#xff0c;看第二步 2.尝试在你打期望停下的代码附近print("1111111")看看是否输出了这个字符串&#xff0c;验证程序确实走到这一步了 3.如果能走到那一步&#xff0c;但是依然没有…

Epipolar-Free 3D Gaussian Splatting for Generalizable Novel View Synthesis 论文解读

目录 一、概述 二、相关工作 1、单场景3DGS 2、跨场景生成3DGS 3、几何方法解决3D任务 三、eFreeSplat 1、预训练跨视角模块 2、无外极线跨视角交互感知模块 3、迭代跨视角高斯对齐 4、高斯参数预测 一、概述 该论文设计了一种不依赖于极线约束的情况实现可推广的新视…

c++视频图像处理

打开视频或摄像头 打开指定视频 /*VideoCapture(const String &filename, apiPreference);filename:读取的视频或者图像序列的名称apiPreference&#xff1a;读取数据时设置的属性*/ VideoCapture video; //定义一个空的视频对象 video.open("H:/BaiduNetdiskDownlo…

青少年强网杯线上ctf-crypto-wp

目录 AliceAES Classics AliceAES 进入环境&#xff0c;给一个key值和一个iv值 意思是&#xff0c;用这两个值AES编码‘Hello,Bob!’,然后把结果输入进去 把key值和iv值带入解得 然后得出flag Classics 题目是下面这个 根据他解码的顺序&#xff0c;反着写出编码顺序 一开…

工具使用_docker容器_crossbuild

1. 工具简介 2. 工具使用 拉取 multiarch/crossbuild 镜像&#xff1a; docker pull multiarch/crossbuild 创建工作目录和示例代码&#xff1a; mkdir -p ~/crossbuild-test cd ~/crossbuild-test 创建 helloworld.c &#xff1a; #include <stdio.h>int main() …

【Linux系统】—— 基本指令(三)

【Linux系统】—— 基本指令&#xff08;三&#xff09; 1 一切皆文件2 重定向操作2.1 初始重定向2.2 重定向的妙用2.3 追加重定向2.4 输入重定向2.5 一切皆文件与重定向结合 3 Linux 中的文件类型4 日志5 「more」命令6 「less」命令7 「head」与「tail」7.1 查看文件开头和结…

搜索引擎中广泛使用的文档排序算法——BM25(Best Matching 25)

在搜索场景中&#xff0c;BM25能计算每个文档与查询的匹配度&#xff0c;从中找出最相关的文档&#xff0c;并按相关性高低排序展示。 要理解BM25&#xff0c;需要掌握以下几个关键概念&#xff1a; 1. 词频&#xff08;Term Frequency, TF&#xff09;&#xff1a;某关键词在文…