动态规划day09(打家劫舍,树形dp)

目录

198.打家劫舍

看到题目的第一想法

看到代码随想录之后的想法

自己实现过程中遇到的困难

213.打家劫舍II

看到题目的第一想法

看到代码随想录之后的想法

自己实现过程中遇到的困难

337.打家劫舍 III(树形dp)

看到题目的第一想法

看到代码随想录之后的想法

自己实现过程中遇到的困难


198.打家劫舍

力扣题目链接(opens new window)

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

  • 示例 1:
  • 输入:[1,2,3,1]
  • 输出:4

解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。   偷窃到的最高金额 = 1 + 3 = 4 。

  • 示例 2:
  • 输入:[2,7,9,3,1]
  • 输出:12 解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。   偷窃到的最高金额 = 2 + 9 + 1 = 12 。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 400
看到题目的第一想法

        dp[j]设置为能偷到的最高金额

        由于相邻的不能偷于是最高金额应该从j-2,j-3种去取

        dp[j] = nums[i]+math.Max(dp[j-2],dp[j-3]);

        最终返回dp[j]与dp[j-1]中的最大值

看到代码随想录之后的想法

        我的想法并没有完全按照dp数组的定义来写,不具备普适性

        代码随想录中,dp的定义为能偷到的最高金额

        则目标元素应该有两种选择

        1 偷目标元素 :若偷目标元素为dp[j-2]+nums[i]

        2 不偷目标元素:若不偷目标元素为dp[j-1]

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

自己实现过程中遇到的困难

        初始化时 dp[0] = nums[0]

                        dp[1] = Math.max(nums[0],nums[1]); 应该是取两者的最大值,才能保证偷到最多

                        我写成了dp[1] = nums[1]

class Solution {/*public int rob(int[] nums) {// 定义dp数组以及每个下标的含义// 到达dp[i] 能偷窃到的最高金额// 确定递归函数// dp[i] = nums[i]+Math.max(dp[i-2],dp[i-3]);// 确定遍历顺序// 从前往后// dp数组初始化// dp[0] = nums[0], dp[1] = nums[1] , dp[2] = nums[2]+nums[0] // dp3 = nums[i]+Math.max(dp[i-2],dp[i-3])// 举例推导dp数组int[] dp = new int[nums.length];if(nums.length==1){return nums[0];}if(nums.length==2){return Math.max(nums[0],nums[1]);}if(nums.length==3){return Math.max(nums[0]+nums[2],nums[1]);}dp[0] = nums[0];dp[1] = nums[1];dp[2] = nums[2] + nums[0];for(int i=3;i<nums.length;i++){dp[i] = nums[i]+Math.max(dp[i-2],dp[i-3]);}return Math.max(dp[nums.length-2],dp[nums.length-1]);}*///卡哥思路public int rob(int[] nums) {//我的方法没有遵循dp数组的定义,dp[i] 代表当前最高金额// 当前最高金额,如果偷当前nums[i] 则dp[i] = nums[i]+dp[i-2]// 如果不偷当前nums[i] 则为dp[i-1]// 定义dp数组以及每个下标的含义// 考虑下标i 能偷到的最高金额// 确定递归函数// 对于nums[i] 我们能考虑是偷还是不偷// 若偷i 则 dp[i] = nums[i]+dp[i-2]// 若不偷i 则 dp[i] = dp[i-1]// dp[i] = nums[i]+Math.max(dp[i-2],dp[i-3]);// 确定遍历顺序// 从前往后// dp数组初始化// dp[0] = nums[0], dp[1] = nums[1] , dp[2] = nums[2]+nums[0] // dp3 = nums[i]+Math.max(dp[i-2],dp[i-3])// 举例推导dp数组int[] dp = new int[nums.length];if(nums.length==1){return nums[0];}if(nums.length==2){return Math.max(nums[0],nums[1]);}dp[0] = nums[0];//这里应该是Math.max(nums[0],nums[1]);我之前直接写成nums[1] 是错误的dp[1] = Math.max(nums[0],nums[1]);for(int i=2;i<nums.length;i++){dp[i] = Math.max(dp[i-2]+nums[i],dp[i-1]);}return dp[nums.length-1];}
}

213.打家劫舍II

力扣题目链接(opens new window)

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。

示例 1:

  • 输入:nums = [2,3,2]

  • 输出:3

  • 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

  • 示例 2:

  • 输入:nums = [1,2,3,1]

  • 输出:4

  • 解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 。

  • 示例 3:

  • 输入:nums = [0]

  • 输出:0

看到题目的第一想法

        和打家劫舍1差不多,只是要考虑首尾

        先处理[0,nums[length-2]]

        再处理[1,nums[length-1]]

        返回两者的最大值

看到代码随想录之后的想法

        和我思路差不多

自己实现过程中遇到的困难

        初始化时 dp[0] = nums[0]

                        dp[1] = Math.max(nums[0],nums[1]); 应该是取两者的最大值,才能保证偷到最多

                        我写成了dp[1] = nums[1]

class Solution {public int rob(int[] nums) {// 确定dp以及每个下标的含义// 第一个房屋和最后一个是紧挨着的// 主要是没办法确定是否加上了第一个// 今晚能偷窃到的最高金额// 我的思路 ,两次dp 一次从第一个到倒数第二个// 一次从第二个到最后一个。// 确定递推函数// dp[i] = Math.max(nums[i]+dp[i-2],dp[i-1]);// 确定遍历顺序// 从前往后// dp数组初始化// dp[0] = nums[0],dp[1]=Math.max(nums[0],nums[1]);// 举例推导dp数组int[] dp1 = new int[nums.length-1];int[] dp2 = new int[nums.length-1];if(nums.length==1){return nums[0];}if(nums.length==2){return Math.max(nums[0],nums[1]);}if(nums.length==3){return Math.max(Math.max(nums[0],nums[1]),nums[2]);}dp1[0] = nums[0];dp1[1] = Math.max(nums[0],nums[1]); dp2[0] = nums[1];dp2[1] = Math.max(nums[1],nums[2]);for(int i=2;i<nums.length-1;i++){dp1[i] = Math.max(dp1[i-1],nums[i]+dp1[i-2]);dp2[i] = Math.max(dp2[i-1],nums[i+1]+dp2[i-2]);}return Math.max(dp1[nums.length-2],dp2[nums.length-2]);}
}

337.打家劫舍 III(树形dp)

力扣题目链接(opens new window)

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

337.打家劫舍III

看到题目的第一想法

        应该使用什么递归思路?前序?后续?

        dp数组要怎么定义?无思路

看到代码随想录之后的想法

        卡哥更多的是考虑二叉树的遍历

        每个节点两种状态,偷该节点,不偷该节点

        要获取偷该节点的最大值,和不偷该节点的最大值

        使用后序遍历,需要通过子节点偷还是不偷,来确定父节点是否要偷

        每层递归通过一个数组dp[2] 来告诉上一层,偷与不偷的值

         new int{偷该层的最大值,不偷该层的最大值}

        父节点通过左右孩子的返回值来确定偷or不偷的最大值,再往上返回

        若该节点要偷:左右孩子不偷的值相加,同时与自己的值相加

        dp[0] = left[0]+right[0]+val

        若该节点不偷:左右孩子偷与不偷的最大值                 

        dp[1] = Math.max(left[0],left[1])+Math.max(right[0],right[1])

        递归三要素

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

             参数为root,返回值为int[]

        2 确定递归函数的终止条件

                若root==null 则return new int[]{0,0}

        3 确定递归函数的执行逻辑

                后序遍历

                先递归执行root.left

                再递归执行root.right

                通过left和right返回的int数组,来确定自身的int[]并返回

        确定dp数组以及下标的含义

        确定递推函数

        dp数组初始化

        确定遍历顺序

        举例推导dp数组

自己实现过程中遇到的困难

        树形dp没见过,考虑在每个递归中新增一个dp[] 来确保内容的传递

        确定每个元素的动作比较关键,比如这个题目就是要你看该层是偷or不偷?

        然后分别讨论

        

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public int rob(TreeNode root) {//卡哥思想// 确定递归的参数和返回值// 参数 root ,返回值 dp[2] // 确定递归的终止条件// 如果为null return {0,0}// 确定递归函数的执行逻辑// 看是否偷当前节点,分为偷or不偷// 这道题是树形dp的基础题目// 使用一个数组,记录两个状态{偷当前的最高金额,不偷当前的最高金额}// 通过父节点看子节点中的金额// 每个节点有两个状态://   偷:子节点不偷,将两个子节点不偷的值(left[1],right[1])+自己节点的值// 不偷:子节点偷or不偷的最大值相加,max(left[0],left[1])+max(right[0],right[1])//确定dp数组和下标的含义// dp[0] 偷的最高金额// dp[1] 不偷的最高金额//用数组来记录小偷能偷取的最大值//确定递推公式// dp[0] = left[1]+right[1]+val;// dp[1] = Math.max(left[0],left[1])+max(right[0],right[1])//DP数组初始化//都为0//确定遍历顺序//后续遍历//举例推导dp数组int[] dp = getMax(root);return Math.max(dp[0],dp[1]);}int[] getMax(TreeNode root){if(root==null){return new int[2];}//后续遍历,左右中int[] left = getMax(root.left);int[] right = getMax(root.right);int[] dp = new int[2];//看是否偷当前的元素//偷当前的元素,则左右不偷dp[0] = left[1]+right[1] + root.val;//不偷当前的元素dp[1] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);return dp;}
}

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

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

相关文章

PLC绝对定位指令DDRVA往复运动(三菱FX系列简单状态机编程)

有关状态机的具体介绍,专栏有很多文章,大家可以通过下面的链接查看: https://rxxw-control.blog.csdn.net/article/details/125488089https://rxxw-control.blog.csdn.net/article/details/125488089三菱FX系列回原功能块介绍 https://rxxw-control.blog.csdn.net/article…

【MATLAB】 HANTS滤波算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 HANTS滤波算法是一种时间序列谐波分析方法&#xff0c;它综合了平滑和滤波两种方法&#xff0c;能够充分利用遥感图像存在时间性和空间性的特点&#xff0c;将其空间上的分布规律和时间上的变化规律联系起来…

怎么把一个网站地址生成二维码?扫码跳网站页面

怎么把一个网站地址生成二维码&#xff1f;现在经常会发现扫描日常生活中的一些二维码会跳转到一个对应的网站页面&#xff0c;那么这种类型的二维码是如何生成的呢&#xff1f;如果大家也想要将网址生成二维码图片使用&#xff0c;那么最简单快捷的方法就是找合适的二维码生成…

单片机中的PWM(脉宽调制)的工作原理以及它在电机控制中的应用。

目录 工作原理 在电机控制中的应用 脉宽调制&#xff08;PWM&#xff09;是一种在单片机中常用的控制技术&#xff0c;它通过调整信号的脉冲宽度来控制输出信号的平均电平。PWM常用于模拟输出一个可调电平的数字信号&#xff0c;用于控制电机速度、亮度、电压等。 工作原理 …

【Maven笔记3】Maven基础入门案例

本篇通过一个最基础的入门案例&#xff0c;熟悉一下maven最基础的使用方法。 编写POM maven项目的核心是pom.xml文件&#xff0c;pom定义了项目的基本信息&#xff0c;用于描述项目如何构建&#xff0c;声明项目依赖等等。 这里我们新建一个maven-demo-hello项目&#xff0c;…

【用队列实现栈】【用栈实现队列】Leetcode 232 225

【用队列实现栈】【用栈实现队列】Leetcode 232 225 队列的相关操作栈的相关操作用队列实现栈用栈实现队列 ---------------&#x1f388;&#x1f388;题目链接 用队列实现栈&#x1f388;&#x1f388;------------------- ---------------&#x1f388;&#x1f388;题目链…

TCP 的三次握手和四次挥手

Java 面试题 TCP 三次握手 第一次握手&#xff1a;客户端向服务端发送SYN包。报文中标志位SYN1&#xff0c;序列号seqx&#xff08;x为随机整数&#xff09;。此时客户端进入了 SYN_SEND 同步已发送状态。 第二次握手&#xff1a;服务端回复客户端SYNACK包。报文中标志位SYN1&…

宿舍管理系统的设计与实现:基于Spring Boot、Java、Vue.js和MySQL的完整解决方案

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

文理导航期刊投稿方式

《文理导航》杂志系国家新闻出版总署批准&#xff0c;内蒙古自治区文旅厅主管&#xff0c;内蒙古自治区北方文化研究院主办的&#xff0c;面向大中专院校、中小学教育的专业性教育刊物&#xff0c;阅读对象是关心教育事业发展的大中专院校、职业教育、中小学教育的专家、教研员…

Flask框架小程序后端分离开发学习笔记《1》网络知识

Flask框架小程序后端分离开发学习笔记《1》网络知识 Flask是使用python的后端&#xff0c;由于小程序需要后端开发&#xff0c;遂学习一下后端开发。 一、网址组成介绍 协议&#xff1a;http&#xff0c;https (https是加密的http)主机&#xff1a;g.cn zhihu.com之类的网址…

嵌入式-Stm32-江科大基于寄存器点亮LED灯

文章目录 前言&#xff1a;一&#xff1a;搭建基于寄存器控制LED的工程二&#xff1a;用江科大的STM32板子实现基于寄存器点亮LED灯三&#xff1a;用非江科大stm32板子实现基于寄存器点亮LED灯道友&#xff1a;一星陨落&#xff0c;黯淡不了星空灿烂&#xff1b;一花凋零&#…

Flume 之自定义 Source

1、简介 Flume 自带 Source 有 Avro、Thrift、Netcat、Taildir、Kafka、Http等&#xff0c;有些场合比如我们指定访问接口获取数据当做 Flume 的 Source&#xff0c;像这种定制化的 Source 需要我们自己实现&#xff0c;下面我将介绍如何自定义实现 Source。 2、自定义实现 Fl…

Git 是什么?

Git 是什么&#xff1f; Git 是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。 Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 Git 与常用的版本控制工具 CVS, Subversion 等不同&#xff0c;…

Cesium 模型压平

最近整理了下手上的代码&#xff0c;以下是对模型压平的说明。 原理是使用了customShader来重新设置了模型的着色器&#xff0c;通过修改模型顶点的坐标来实现了压平。 废话不多说&#xff0c;下面上代码&#xff1a; /*** class* description 3dtiles模型压平*/ class Flat…

推荐给前端程序员的5款浏览器插件

所谓“工欲善其事&#xff0c;必先利其器”。Chrome&#xff08;谷歌浏览器&#xff09; 应该是程序员或者互联网行业人员使用最多的浏览器了。而在日常开发中&#xff0c;下面几款 浏览器 扩展也许能让你的开发工作事半功倍 。 1、Vimium vimium 是一个旨在将你的双手从鼠标…

C++核心编程(包含:内存、函数、引用、类与对象、文件操作等)【持续更新】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;C从基础到进阶 C核心编程&#x1f30f;1 内存分区模型&#x1f384;1.1 程序运行前&#x1f384;1.2 程序运行后&#x1f384;1.3 new操作符 &#x1f30f;2 引用&#x1f384;2.1 引用的基…

【Golang开源项目】Golang高性能内存缓存库BigCache设计与分析

项目地址 BigCache 是一个快速&#xff0c;支持并发访问&#xff0c;自淘汰的内存型缓存&#xff0c;可以在存储大量元素时依然保持高性能。BigCache将元素保存在堆上却避免了GC的开销。 背景介绍 BigCache的作者在项目里遇到了如下的需求&#xff1a; 支持http协议支持 10…

Linux shell编程学习笔记39:df命令

0 前言1 df命令的功能、格式和选项说明 1.1 df命令的功能1.2 df命令的格式1.3 df命令选项说明 2 df命令使用实例 2.1 df&#xff1a;显示主要文件系统信息2.2 df -a&#xff1a;显示所有文件系统信息2.3 df -t[]TYPE或--type[]TYPE&#xff1a;显示TYPE指定类型的文件系统信…

解决英特尔无线网卡WiFi或者蓝牙突然消失问题

winR&#xff0c;输入“devmgmt.msc”&#xff0c;检查设备管理器中的无线网卡驱动是否安装好。 访问https://www.intel.cn/content/www/cn/zh/download/19351/windows-10-and-windows-11-wi-fi-drivers-for-intel-wireless-adapters.html下载对应系统版本的英特尔无线网卡WiFi…

遇到问题不要慌,轻松搞定内存泄露

当一个系统在发生 OOM 的时候&#xff0c;行为可能会让你感到非常困惑。因为 JVM 是运行在操作系统之上的&#xff0c;操作系统的一些限制&#xff0c;会严重影响 JVM 的行为。故障排查是一个综合性的技术问题&#xff0c;在日常工作中要增加自己的知识广度。多总结、多思考、多…