代码随想录算法训练营第四十七天 | LeetCode 198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III

代码随想录算法训练营第四十七天 | LeetCode 198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III

文章链接:打家劫舍 打家劫舍 II 打家劫舍 III
视频链接:打家劫舍 打家劫舍 II 打家劫舍 III

1. LeetCode 198. 打家劫舍

1.1 思路

  1. 我们要去偷钱,但相邻房间不能偷,求最后偷的最大金额。其实我们对于当前房间偷不偷是取决于前一个和前前一个房间的,是一个递推的关系。
  2. dp 数组及其下标的含义:dp[i] 考虑下标 i(包含下标 i),所能偷的最多的金额为 dp[i],最终结果在 dp[nums.length-1]。注意我们是考虑,考虑的仅仅是遍历的范围,取不取由递推公式决定
  3. 递推公式:偷 i 和不偷 i。偷 i 就是只能考虑前前一个房间,即 dp[i-2]+nums[i],i-2 之前的范围加上 i 就是我们的考虑范围。不偷 i 就是考虑前一个房间,即 dp[i-1],i-1 之前的范围就是我们的考虑范围。因此递推公式:dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1])
  4. dp 数组的初始化:根据递推公式,我们的基础就是 dp[0] 和 dp[1],dp[0] 就只能是偷 nums[0],dp[1] 是考虑下标 1 之前的包括下标 1,1 和 0 两个位置取最大值 dp[1]=Math.max(nums[1],nums[0]),其余下标初始化为 0 即可,不影响
  5. 遍历顺序:根据递推公式,就是从前往后比那里的 for(int i=2;i<nums.length;i++)

1.2 代码

// 动态规划
class Solution {
	public int rob(int[] nums) {
		if (nums == null || nums.length == 0) return 0;
		if (nums.length == 1) return nums[0];

		int[] dp = new int[nums.length];
		dp[0] = nums[0];
		dp[1] = Math.max(dp[0], nums[1]);
		for (int i = 2; i < nums.length; i++) {
			dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
		}

		return dp[nums.length - 1];
	}
}

2. LeetCode 213. 打家劫舍 II

2.1 思路

  1. 本题和198. 打家劫舍的区别就是环了,之前是一个线性的数组,本题是把这个数组连成环了,首尾相连,其余的都是相同的。关于连成环首尾怎么取,我们可以分成下面三种情况:
  2. 情况 1:首尾都不取,只取中间部分,对于数组是否连成环跟这种情况没有关系,就相当于是线性数组了,直接和我们在198. 打家劫舍处理方式一样
  3. 情况 2:考虑首元素不考虑尾元素,就相当于默认数组没有尾元素了,这样对于数组是否连成环也没有关系了
  4. 情况 3:不考虑首元素考虑尾元素,就相当于默认数组没有首元素了,这样对于数组是否连成环也没有关系了
  5. 关于连成环就是分成了以上三种情况了,但是情况 2 和 3 是包含 1 的。情况 1 是考虑中间部分,情况 2 是考虑首+中间部分,情况 3 是考虑尾+中间部分。注意我们是考虑,不是一定要取,考虑的仅仅是遍历的范围,取不取是由递推公式决定的。因此我们只要求情况 2 的最优解和情况 3 的最优解,两者取最大值即可。我们可以把情况 2 和情况 3 分别传到198. 打家劫舍函数里得到这个线性数组的最大值,两者再取最大值

2.2 代码

class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0)
            return 0;
        int len = nums.length;
        if (len == 1)
            return nums[0];
        return Math.max(robAction(nums, 0, len - 1), robAction(nums, 1, len));
    }

    int robAction(int[] nums, int start, int end) {
        int x = 0, y = 0, z = 0;
        for (int i = start; i < end; i++) {
            y = z;
            z = Math.max(y, x + nums[i]);
            x = y;
        }
        return z;
    }
}

3. LeetCode 337. 打家劫舍 III

3.1 思路

  1. 本题和前面不一样的是我们是在一个二叉树上偷,要求也是相邻节点不能偷,就相当于是树形 dp,因此也用到了之前的递归三部曲
  2. dp 数组及其下标的含义:每个节点只有两个状态,偷与不偷,用一个长度为 2 的 dp 数组就可以表示了,dp[0]=不偷,dp[1]=偷。因为我们在遍历二叉树的过程中是通过递归遍历的,系统栈会保存每一层递归里的参数,每一层递归都有一个长度为 2 的 dp 数组,当前层 dp 数组就是表示当前层所遍历这个节点的状态,dp[0] 就是不偷所得的最大金额,dp[1] 就是偷所得的最大金额。而我们是通过后序遍历从底向上遍历的,最后就是根节点偷与不偷两个状态取最大值
  3. 递归函数的参数和返回值:返回值是一个 dp 数组,一维的,长度为 2,参数是 root。我们是通过一个数组来接收这个函数的返回值的。最终是 return Math.max(数组 [0],数组 [1])两个状态取最大值
  4. 递归函数的终止条件:if(root==null)此时偷与不偷的最大金额都是 0,因为是空节点
  5. 遍历顺序:偷与不偷取一个最大值。偷当前节点,左右孩子就不能偷了 int value1=root.val+leftdp[0]+rightdp[0]。这里的leftdp 和rightdp 就是我们通过后序遍历从底往上推的过程得到的,因此要在上面定义 dp 数组 leftdp 和rightdp 通过递归运算得到 leftdp=递归函数(root.left),rightdp=递归函数(root.right),这样就得到了左右孩子偷与不偷的最大值,因此就能得到当前节点偷与不偷的最大值,当前节点偷了那左右孩子就不能偷 int value1=root.val+leftdp[0]+rightdp[0],当前节点不偷那左右孩子考虑能偷,偷不偷取决于左右孩子偷与不偷的最大值是什么,dp[0] 和 dp[1] 哪个大就取哪个 int value2=Math.max(leftdp[0],leftdp[1])+Math.max(rightdp[0],rightdp[1]),最终 return value2,value1 组成的数组,注意两个的位置。并且我们上面的逻辑是"左右中",即后序遍历的逻辑
    在这里插入图片描述

3.2 代码

// 3.状态标记递归
    // 执行用时:0 ms , 在所有 Java 提交中击败了 100% 的用户
    // 不偷:Max(左孩子不偷,左孩子偷) + Max(又孩子不偷,右孩子偷)
    // root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) +
    // Math.max(rob(root.right)[0], rob(root.right)[1])
    // 偷:左孩子不偷+ 右孩子不偷 + 当前节点偷
    // root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
    public int rob3(TreeNode root) {
        int[] res = robAction1(root);
        return Math.max(res[0], res[1]);
    }

    int[] robAction1(TreeNode root) {
        int res[] = new int[2];
        if (root == null)
            return res;

        int[] left = robAction1(root.left);
        int[] right = robAction1(root.right);

        res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        res[1] = root.val + left[0] + right[0];
        return res;
    }
}

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

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

相关文章

【论文阅读】Generating Radiology Reports via Memory-driven Transformer (EMNLP 2020)

资料链接 论文原文&#xff1a;https://arxiv.org/pdf/2010.16056v2.pdf 代码链接&#xff08;含数据集&#xff09;&#xff1a;https://github.com/cuhksz-nlp/R2Gen/ 背景与动机 这篇文章的标题是“Generating Radiology Reports via Memory-driven Transformer”&#xf…

Leetcode—2586.统计范围内的元音字符串数【简单】

2023每日刷题&#xff08;二十二&#xff09; Leetcode—2586.统计范围内的元音字符串数 实现代码 class Solution { public:int vowelStrings(vector<string>& words, int left, int right) {int ans 0;for(int i left; i < right; i) {string s words[i];i…

解决:ImportError: cannot import name ‘get_config‘

解决&#xff1a;ImportError: cannot import name ‘get_config’ 背景 今天使用Conda构建项目运行环境的时候报错&#xff1a;ImportError: cannot import name ‘get_config’ ##报错问题 from keras.callbacks import LearningRateScheduler, ModelCheckpointFile "D…

GreenPlum简介

简介 Greenplum是一家总部位于**美国加利福尼亚州&#xff0c;为全球大型企业用户提供新型企业级数据仓库(EDW)、企业级数据云(EDC)和商务智能(BI)提供解决方案和咨询服务的公司&#xff0c;在全球已有&#xff1a;纳斯达克&#xff0c;纽约证券交易所&#xff0c;Skype. FOX&…

idea 模板参数注释 {@link}

1. 新增组 2. 设置方法注释及变量 增加模板文本 ** * $param$ * return {link $return$} */3. 设置变量表达式 勾选跳过param 参数表达式 groovyScript("def result ;def params \"${_1}\".replaceAll([\\\\[|\\\\]|\\\\s], ).split(,).toList();def param…

7.spark sql编程

目录 概述RDD ,Datasets,DataFrames 之间的区别Datasets , DataFrames和 RDD 入门people.jsonSparkSession创建 DataFramesDataFrame 操作编程方式运行 sql 查询创建 DatasetsDataFrames 与 RDDs 互相转换使用反射推断模式编码问题 编程指定 Schema官方文档的代码不全问题 结束…

idea使用gradle教程 (idea gradle springboot)2024

这里白眉大叔&#xff0c;写一下我工作时候idea怎么使用gradle的实战步骤吧 ----windows 环境----------- 1-本机安装gradle 环境 &#xff08;1&#xff09;下载gradle Gradle需要JDK的支持&#xff0c;安装Gradle之前需要提前安装JDK8及以上版本 https://downloads.gra…

Python - 面向现实世界的人脸复原 GFP-GAN 简介与使用

目录 一.引言 二.GFP-GAN 简介 1.GFP-GAN 数据 2.GFP-GAN 架构 3.GFP-GAN In Wave2Lip 三.GFPGAN 实践 1.环境搭建 2.模型下载 3.代码测试 4.测试效果 四.总结 一.引言 近期 wav2lip 大火&#xff0c;其通过语音驱动唇部动作并对视频质量进行修复&#xff0c;其中…

【微信小程序】新版获取手机号码实现一键登录(uniapp语法)(完整版附源码)

需求 如图&#xff0c;点击按钮&#xff0c;获取用户手机号实现一键登录&#xff0c;当然&#xff0c;用户也可以自行输入其他手机号进行登录 问题 要想获取用户手机号并不复杂&#xff0c;但由于近几年微信小程序获取手机号的api进行了更新&#xff0c;当前很多帖子使用的…

VB.NET—DataGridView控件教程详解

目录 前言: 过程: 第一步: 第二步: 第三步: 第四步: 第五步&#xff1a; 番外篇: 总结: 前言: DataGridView是.NET FormK中的一个Windows窗体控件&#xff0c;它提供了一个可视化的表格控件&#xff0c;允许用户以表格形式显示和编辑数据。它通常用于显示和编辑数据库…

Rust教程5:泛型和特征

文章目录 泛型函数特征特征泛型 Rust系列&#xff1a;初步⚙所有权⚙结构体和枚举类⚙函数进阶 泛型函数 Rust采纳了C中的泛型机制&#xff0c;并且形式上也几乎借鉴了C&#xff0c;示例如下 fn add<T: std::ops::Add<Output T>>(a:T, b:T) -> T {a b } fn…

Java智慧工地管理平台可视化大数据建造工地APP源码

建筑行业是国民经济的重要物质生产部门和支柱产业之一&#xff0c;同时&#xff0c;建筑业也是一个安全事故多发的高危行业。如何加强施工现场安全管理、降低事故发生频率、杜绝各种违规操作和不文明施工、提高建筑工程质量&#xff0c;是摆在各级政府部门、施工企业面前的一道…

一文学会Scala【Scala一站式学习笔记】

文章目录 为什么要学习Scala语言什么是Scala如何快速掌握Scala语言Scala环境安装配置Scala命令行 Scala的基本使用变量数据类型操作符if 表达式语句终结符循环高级for循环 Scala的集合体系集合SetListMapArrayArrayBuffer数组常见操作Tuple总结 Scala中函数的使用函数的定义函数…

Python+Selenium+Unittest 之selenium12--WebDriver操作方法2-鼠标操作1(ActionChains类简介)

在我们平时的使用过程中&#xff0c;会使用鼠标去进行很多操作&#xff0c;比如鼠标左键点击、双击、鼠标右键点击&#xff0c;鼠标指针悬浮、拖拽等操作。在selenium中&#xff0c;我们也可以去实现常用的这些鼠标操作&#xff0c;这时候就需要用到selenium中的ActionChains类…

Android transform旋转rotate圆角矩形图roundedCorners,Kotlin

Android transform旋转rotate圆角矩形图roundedCorners&#xff0c;Kotlin import android.graphics.Bitmap import android.os.Bundle import android.util.Log import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import com.bumptech.glide.…

【IO多路转接】pollepoll

文章目录 1 :peach:poll:peach:1.1 :apple:poll函数接口:apple:1.2 :apple:poll接口的使用:apple:1.3 :apple:poll的优缺点:apple: 2 :peach:epoll:peach:2.1 :apple:epoll函数接口:apple:2.1.1 :lemon:epoll_create:lemon:2.1.2 :lemon:epoll_ctl:lemon:2.1.3 :lemon:epoll_wa…

pcie对phy的skew要求

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 pcie的设计中有这样一条要求&#xff0c;所有但phy/tx*_clk pin的clock skew要小于skew要求。 这里提供一下实现方法&#xff0c;如果你有更好的办法可以在评论区留言或者私信…

利用maven的dependency插件将项目依赖从maven仓库中拷贝到一个指定的位置

https://maven.apache.org/plugins/maven-dependency-plugin/copy-dependencies-mojo.html 利用dependency:copy-dependencies可以将项目的依赖从maven仓库中拷贝到一个指定的位置。 使用默认配置拷贝依赖 如果直接执行mvn dependency:copy-dependencies&#xff0c;是将项目…

IP地址与MAC地址(硬件地址)的区别

IP地址和硬件地址都是用于标识网络设备的地址&#xff0c;但它们的作用和使用方式不同。IP地址是用于在网络中唯一标识一个设备的逻辑地址它是由网络协议栈分配的&#xff0c;可以动态地分配和改变。而硬件地址是设备的物理地址&#xff0c;也称为MAC地址&#xff0c;是由设备制…

TCP/IP的基础知识

文章目录 TCP/IP的基础知识硬件&#xff08;物理层&#xff09;网络接口层&#xff08;数据链路层&#xff09;互联网层&#xff08;网络层&#xff09;TCP/IP的具体含义传输层应用层&#xff08;会话层以上的分层&#xff09;TCP/IP分层模型与通信示例发送数据包的一个例子接收…