java数据结构与算法刷题-----LeetCode337. 打家劫舍 III

news2024/11/18 5:33:37
java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

文章目录

    • 1. 动态规划+深度优先
      • 1.1 解题思路和细节
      • 2.2 代码实现

很多人觉得动态规划很难,但它就是固定套路而已。其实动态规划只不过是将多余的步骤,提前放到dp数组中(就是一个数组,只不过大家都叫它dp),达到空间换时间的效果。它仅仅只是一种优化思路,因此它目前的境地和线性代数一样----虚假的难。

  1. 想想线性代数,在国外留学的学生大多数不觉得线性代数难理解。但是中国的学生学习线性代数时,完全摸不着头脑,一上来就是行列式和矩阵,根本不知道这玩意是干嘛的。
  2. 线性代数从根本上是在空间上研究向量,抽象上研究线性关系的学科。人家国外的教科书都是第一讲就帮助大家理解研究向量和线性关系。
  3. 反观国内的教材,直接把行列式搞到第一章。搞的国内的学生在学习线性代数的时候,只会觉得一知半解,觉得麻烦,完全不知道这玩意学来干什么。当苦尽甘来终于理解线性代数时干什么的时候,发现人家国外的教材第一节就把这玩意讲清楚了。你只会大骂我们国内这些教材,什么狗东西(以上是自己学完线性代数后的吐槽,我们同学无一例外都这么觉得)。

而我想告诉你,动态规划和线性代数一样,我学完了才知道,它不过就是研究空间换时间,提前将固定的重复操作规划到dp数组中,而不用暴力求解,从而让效率极大提升。

  1. 但是网上教动态规划的兄弟们,你直接给一个动态方程是怎么回事?和线性代数,一上来就教行列式和矩阵一样,纯属恶心人。我差不多做了30多道动态规划题目,才理解,动态方程只是一个步骤而已,而这已经浪费我很长时间了,我每道题都一知半解不理解,过程及其痛苦。最后只能重新做。
  2. 动态规划,一定是优先考虑重复操作与dp数组之间的关系,搞清楚后,再提出动态方程。而你们前面步骤省略了不讲,一上来给个方程,不是纯属扯淡吗?
  3. 我推荐研究动态规划题目,按5个步骤,从上到下依次来分析
  1. DP数组及下标含义
  2. 递推公式
  3. dp数组初始化
  4. 数组遍历顺序(双重循环及以上时,才考虑)
  5. dp数组打印,分析思路是否正确(相当于做完题,检查一下)

在这里插入图片描述

1. 动态规划+深度优先

1.1 解题思路和细节

题目细节
  1. 想要偷到最多的钱,一定要遵循,适当取舍
  2. 比如上一个结点没偷,那么这个结点也不一定非要偷,因为你这个不偷,下一个就可以偷。
  3. 所以使用深度优先遍历,对于每个结点,都有两个选择,偷与不偷,而相邻的多个结点直接,不用非得隔一个偷一个,而是选择最大的方案。

比如100,1,2,3,4,100. 如果隔一个偷一个的话为100,1,2,3,4 = 106,100或100,1,2,3,4,100 = 104,但是如果是100,1,2,3,4,100 = 203明显是最大的方案.

  1. 特别注意:无论选择偷与不偷,都需要将左右子结点相加,因为只是相邻的结点不能偷,而不是整个子树都不能偷
图解
  1. 以此为例:其中dp数组含义是dp[当前结点偷的话当前共偷多少,不偷共偷多少]
    在这里插入图片描述
  2. 对于深度优先遍历的第一个结点为,左下角的3
    在这里插入图片描述
  1. 它的左子树是null,所以左子树偷与不偷都是0元,故其左子树的dp数组为dp[0,0],表示左子树偷的话共偷0元,不偷的话共偷0元
  2. 它的右子树是null,一样偷不偷都是0,故其右子树dp为dp[0,0]
  3. 它本身是3,所以偷的话就是+3.不偷的话就不加3
  1. 偷当前结点,那么左子树和右子树都不能偷,左子树不偷的话是0,右子树不偷也是0,合起来为0+0=0,因为都是0,所以就拿到0.加上当前结点3 共偷3元
  2. 不偷当前结点,那么左子树和右子树可以偷,左子树偷根结点和不偷都有0,右子树偷也是0,两棵子树都选最大的,合起来为0+0=0,当前结点也不偷,共偷0元
  1. 最终得到当前结点dp数组为dp[3,0],表示偷当前结点,不能偷两个直接儿子共获取3元,不偷当前结点偷左右儿子结点可偷0元
  1. 第二个遍历结点为它上面的2
    在这里插入图片描述
  1. 左子树为null,偷和不偷可获利[0,0]
  2. 右子树为3,偷和不偷分别获利[3,0]
  3. 当前结点如果偷,则+2,不偷则不加
  1. 偷当前结点,则左子树和右子树不能偷,左子树不偷为0,右子树不偷为0,合起来为0,则偷当前结点+2,获利2元
  2. 不偷当前结点,则左子树和右子树可以偷,左子树偷和不偷都为0,右子树偷为3,不偷为0,左右子树都选大的方案合为0+3 = 3,则不偷当前结点,获利3
  1. 因此当前结点dp为dp[2,3],表示偷当前结点的话,一共获利2元,不偷当前节点,共获利3元
  1. 第3个遍历的结点是右下角的1,同理,左右子树都为null,则偷当前结点为1,不偷为0,故dp[1,0]
  2. 第4个遍历的是右下角1的父结点3,同理,左子树为null,右子树为1,dp[1,0],故当前结点dp[3,1].表示偷当前结点,下面1不偷,为3.不偷当前结点,偷下面那个1为1
  3. 最后是根结点3
    在这里插入图片描述
  1. 如果偷当前结点
  1. 则左子结点不能偷,左子结点dp为[2,3],也就是不偷它,共有为3
  2. 右子结点也不能偷,为1
  3. 则,偷当前结点的3,加上左子结点不偷共有3,右子结点不偷共有1,加起来为7.
  1. 不偷当前结点
  1. 左子结点可以偷也可以不偷,偷有2,不偷为3,选大的3
  2. 右子结点,偷有3,不偷为1,选大的共有3
  3. 不偷当前结点为0,加上左子结点不偷,共有3,右子结点偷,共有3。加起来为6
  1. 故,根节点dp为dp[7,6]
  1. 最终,因为我们要偷最多的钱,所以选择dp[7,6]中大的那个,为7
动态规划5步曲
  1. DP数组及下标含义
  1. 我们要求出的是二叉树相邻结点不能都偷的情况下,最多偷多少钱。显然dp数组中存储的是相邻结点如果偷,能偷多少钱,不偷相邻的,而偷当前结点能有多少钱。要求出谁的?显然是求出,以当前结点来看,前面一个结点偷还是不偷。那么下标就是代表前一个结点偷还是不偷,很显然,只需要一个下标,也就是一维数组。而且这个一维数组只有两个元素,代表偷和不偷
  1. 递推公式
  1. 假设left[a,b]表示左子树中偷了左儿子,共有left[a]元,不偷左儿子,共有left[b]元,同理right[a,b]为右子树
  2. 当前结点偷的话,左右儿子不能偷,不偷左儿子为left[b],不偷右儿子为right[b]。
  3. 当前结点不偷,左右儿子可以偷也可以不偷,偷左儿子为left[a],不偷为left[b],偷右儿子为right[a],不偷为right[b]
  4. 故dp[n] = [本身 + left[b] + right[b] ,max{ left[a] , left[b] } + max{ right[a] , right[b] }.也就是当前结点,偷的话,就是本身+左子树不偷左儿子+右子树不偷右儿子。不偷当前结点,就是左子树偷左儿子或不偷左儿子选大的+右子树偷或不偷右儿子选大的
  1. dp数组初始化

在这里插入图片描述

  1. 数组遍历顺序(单重循环,无需考虑遍历顺序,一共就一维,哪里来的谁先谁后)
  2. 打印dp数组(自己生成dp数组后,将dp数组输出看看,是否和自己预想的一样。)

在这里插入图片描述

2.2 代码实现

代码

在这里插入图片描述

class Solution {
    public int rob(TreeNode root) {
        int[] dp = dfs(root);//获取dp数组
        return Math.max(dp[0],dp[1]);//返回最后一个房子偷与不偷,最大的结果
    }
    //int[]{偷当前结点最大获利,不偷当前结点最大获利}
    int[] dfs(TreeNode root){
        if (root == null)return new int[]{0,0};//如果没的遍历,就返回0,0,表示偷和不偷当前结点都是获利0,因为没有这个房子
        int[] left = dfs(root.left);//获取左子树dp数组
        int[] right = dfs(root.right);//获取右子树dp数组
        //如果偷当前结点,则只有一种选择,就是不偷左右子树根节点
        int yes = root.val+ left[1] + right[1];
        //如果不偷当前房子,则左右子树都需要偷
        //左子树我们偷根结点,和不偷根节点,选大的
        //右子树我们也可以选择偷根节点,或不偷,选大的
        int no = Math.max(left[0],left[1]) + Math.max(right[0],right[1]);
        //返回当前结点偷和不偷
        return new int[]{yes,no};
    }
}

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

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

相关文章

vue项目中使用antvX6新手教程,附demo案例讲解(可拖拽流程图、网络拓扑图)

前言: 之前分别做了vue2和vue3项目里的网络拓扑图功能,发现对antv X6的讲解博客比较少,最近终于得闲码一篇了! 需求: 用户可以自己拖拽节点,节点之间可以随意连线,保存拓扑图数据后传给后端&…

恒峰|智能高压森林应急消防泵|森林防火的守护神

在大自然中,森林是生态系统的重要组成部分,它们为我们提供氧气、净化空气、保持水源、防止土壤侵蚀等重要功能。然而,森林火灾却时常威胁着这些宝贵资源的安全。为了应对这一挑战,我们研制出了一种名为“智能高压森林应急消防泵”…

游戏寻路之A*算法(GUI演示)

一、A*算法介绍 A*算法是一种路径搜索算法,用于在图形网络中找到最短路径。它结合了Dijkstra算法和启发式搜索的思想,通过综合利用已知的最短路径和估计的最短路径来优化搜索过程。在游戏自动寻路得到广泛应用。 二、A*算法的基本思想 在图形网络中选择一个起点和终点。维护…

OSPF 普通区域stub实验简述

1、OSPF 普通区域stub配置 实验拓扑图 r1: sys sysname r1 undo info enable int loopb 0 ip add 1.1.1.1 32 quit int e0/0/0 ip add 172.16.1.1 24 quit ospf 1 area 0.0.0.1 network 172.16.1.0 0.0.0.255 network 1.1.1.1 0.0.0.0 Stub 配置普通区域 ret r6: sys sysnam…

不愧是华为出来的,太厉害了...

🍅 视频学习:文末有免费的配套视频可观看 🍅 关注公众号【互联网杂货铺】,回复 1 ,免费获取软件测试全套资料,资料在手,涨薪更快 实习去了博彦科技(外包),做的…

认识AJAX

一、什么是Ajax? 有跳转就是同步,无跳转就是异步 Asynchronous Javascript And XML(异步JavaScript和XML) Ajax 异步 JavaScript 和XML。Ajax是一种用于创建快速动态网页的技术通过在后台与服务器进行少量数据交换,Ajax可以使网…

SpringMVC01、回顾MVC

1、回顾MVC 1.1、什么是MVC MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式,MVC是一种架构模式。…

基本运算符

参考C Primer Plus进行C语言学习 文章目录 基本运算符 除法运算符:/其他运算 1、除法运算符 在C语言中,整数除法结果的小数部分被丢弃,这一过程被称为截断。 2.其他运算符 (1)sizeof运算符和size_t类型 回顾一下&…

代码随想录算法训练营三刷day13 |栈与队列 之 239. 滑动窗口最大值 347.前 K 个高频元素

三刷day13 239. 滑动窗口最大值347.前 K 个高频元素 239. 滑动窗口最大值 题目链接 解题思路: 设计单调队列的时候,pop和push操作要保持如下规则: pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队…

Jumpserver堡垒机搭建

Jumpserver概述: Jumpserver优势:

DevOps学习 | 如何应对IT服务交付中的问题?

目录 前言 DevOps是什么? DevOps发展历程 DevOps与微服务、容器的关系 书本推荐 前言 作为一个热门的概念,DevOps这个名词在程序员社区里频频出现,备受技术大佬们的追捧。甚至网络上有了“南无DevOps”的戏言(南无在梵语的意…

(学习日记)2024.03.04:UCOSIII第六节:main函数+前六节总结

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…

连锁线上线下门店管理为什么需要使用分账系统

连锁线上线下门店管理的复杂性要求采用有效的分账系统,以实现降低税务风险、保障资金安全和合规运营。首先,通过分账系统,可以清晰记录不同门店的收入和支出情况,有利于确保税务合规性。其次,分账系统有助于将不同门店…

Scratch 第十六课-弹珠台游戏

第十六课-弹珠台游戏 大家好,今天我们一起做一款弹珠台scratch游戏,我们也可以叫它弹球游戏!这款游戏在刚出来的时候非常火爆。小朋友们要认真学习下! 这节课的学习目标 物体碰撞如何处理转向问题。复习键盘对角色的控制方式。…

23.基于springboot + vue实现的前后端分离-在线旅游网站系统(项目 + 论文PPT)

项目介绍 本旅游网站系统采用的数据库是MYSQL ,使用 JSP 技术开发,在设计过程中,充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。 技术选型 后端: SpringBoot Mybatis 数据库 : MyS…

Django官网项目 二

官网地址:Writing your first Django app, part 2 | Django documentation | Django 创建模组: 注册model (bug:没有加后面的逗号) 在manage.py 的目录下: python manage.py makemigrations polls pyth…

打印机状态错误的解决方法

在电脑操作中,用户遇到打印机状态错误的问题,但不知道怎么操作才可以解决问题?接下来小编介绍打印机状态错误的解决方法,帮助大家轻松解决打印机出现错误状态的问题,快速恢复打印机的正常工作状态,从而满足…

固定资产管理系统建设方案

固定资产管理系统需求要点: 1. 实现公司内部固定资产管理全生命周期管理,包括资产采购、资产入库、资产领用、资产借用、资产归还、资产报废、资产维修、资产调拨等全过程管理。 2. 可实现集团内部固定资产盘点管理,包括盘点计划、盘点查询等…

多平台拼音输入法软件的开发

拼音输入法从上个世纪发展到现在, 已经发展了几十年了, 技术上已经非常成熟了. 换句话说, 就是实际上没多少技术含量, 随便来个人就能手搓一个. 本文介绍一个简单的多平台拼音输入法软件的设计和实现, 支持 GNU/Linux (ibus) 平台 (PC) 和 Android 平台 (手机). 目录 1 中文输…

【C++庖丁解牛】默认成员函数

📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 目录 前言1. 构造函数1.1 …