【小白友好】LeetCode 打家劫舍 III

https://leetcode.cn/problems/house-robber-iii/description/

前言

建议还是先看看动态规划的基础题再看这个。动态规划是不刷题,自己100%想不出来的
基础题:

  • 最大子数组和
  • 乘积最大子数组
  • 最长递增子序列
  • 最大升序子数组和

小白想法

现在我们想遍历的数据结构不是数组了,而是一颗树。在树上的dp叫做“树形dp”(so called)。
那在遍历寻找解更新dp的时候无非就是用遍历树的dfs那一套了,不再是for i in range(length)了。

现在不方便用dp数组去存储dp的值了,毕竟这是个树。那用什么?我们之前之所以用数组,是因为使用dp[i]能够直接取到遍历到nums[i]时dp的值,之前的dp数组实际上充当的是一个hash table(字典、map…随便你怎么叫)的作用。 那我们就直接用字典就好啦!不再用数组了。

然后能不能像for i in range(length)一样“从前往后”边遍历边更新?树上的“从前往后”是什么?是从叶子走向根

有了前几点的铺垫,下面正式进入状态转移方程的构建。

还能不能像以前“打家劫舍”那个题一样通过选择前几个状态来更新dp?
看上去好像可以。但是请注意我们现在的“dp数组”不是数组了,而是一个字典。字典的key是node,value是dp值。如果是数组,我们可以很方便的通过i-1,i-2指针来访问前面的状态,但是此时的字典已经不适合了。 当前的状态i和前面时刻-2的“联系”已经没有了。

题外话,莫非我可以先把“树形”的数据先压成一个数组,然后再套用之前的思路?想法很好,甚至也能做,但是写起来比较麻烦,下一个!

就算是有联系,在当前节点时,需要考虑 自己2个孩子是否被偷,没偷就有可能跟孙子一起被偷,共计6个节点,我相信写起来也挺复杂,要max很多次。

dead end after all…

题解,学习

换个dp数组的意义吧!我们不拘泥于过去的思路了。
在之前做“最大连乘子数组”的时候我们不是也用了2个dp数组吗?

把dp拆开成2个,分成 选择了子节点的最大值,和没选择了子节点的最大值。请注意树上的“从前往后”是从叶子到根。把这2个dp分别叫做dp_selecteddp_unselected

先考虑最简单的情况,从最前面开始,只有一个叶子的时候,2个dp的值很好知道,叶子值或者0。

而当到了树上的分支now的时候,dp_selected[now]的意义是选择当前节点,那么应该等于自己当前节点的值+没选自己孩子的最大dp值:now.val+dp_unselected[now.left]+dp_unselected[now.right],只有这 一种情况,是因为相邻的父子不能一起选;而dp_unselected[now]就比较多了:由于我当前节点没选择,那么我的孩子可以选,也可以不选,那我要当前最大的,要取他们的最大值更新。

上面写的比较“大白话”,我个人感觉用数学公式表达起来比较简洁易懂。。

以下为官方题解
在这里插入图片描述

接下来就是遍历,然后通过转移方程一边遍历一边更新就行。

代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def rob(self, root: Optional[TreeNode]) -> int:# dp的存储形式变了,变成字典# dp的意义变了,不再是“以xx结尾的结果”from collections import defaultdictdp_selected,dp_unselected=defaultdict(int),defaultdict(int)def travel_tree(now):if now is None:return travel_tree(now.left)travel_tree(now.right)left=now.leftright=now.rightres1=now.val+dp_unselected[left]+dp_unselected[right]res2=max(dp_selected[left],dp_unselected[left])+max(dp_selected[right],dp_unselected[right])dp_selected[now]=res1# 可以选择不更新,因为不更新他就是0# 在节点选择的过程中,0是肯定会被丢弃的dp_unselected[now]=res2return travel_tree(root)return max(dp_selected[root],dp_unselected[root])

defaultdict的作用是给予在dict中不存在的key一个初始值,简化代码。

提交,过了。

想不出来,不刷题真的想不出来。

优化

显然dp的hash table是很重要的,但是我们能不能把他也优化掉,不使用他的额外的空间呢?
我们可以从转移方程看到,当前点的更新只跟自己孩子的那几个值有关。

这熟悉的配方!在dp[i]只跟dp[i-1]有关时,我们也能通过类似的方法只保留上一个dp的值来优化空间。

那么怎么只保留上一个dp的值呢?我们上一个dp的值是“选左孩子的最大值”、“不选左孩子的最大值”、“选右孩子的最大值”、“不选右孩子的最大值”,一共4个,使用函数返回给父节点就可以了!(毕竟除了使用额外的空间,函数返回值是唯一父子能交流的东西了)

class Solution:def rob(self, root: Optional[TreeNode]) -> int:def travel_tree(now):if now is None:  return 0, 0  l_rob, l_not_rob = travel_tree(now.left)r_rob, r_not_rob = travel_tree(now.right)rob = l_not_rob + r_not_rob + node.val  # 选not_rob = max(l_rob, l_not_rob) + max(r_rob, r_not_rob)  # 不选return rob, not_robreturn max(travel_tree(root))  # 根节点选或不选的最大值

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

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

相关文章

前端语义化标签及实例

常用的语义化标签的以下几种&#xff1a; header、nav、article、section、aside、footer、abbr、dfn、address、del、ins、pre、meter、progress <header> 定义文章的页眉信息 <header><h1>我的网站标题</h1><nav><ul><li><a …

[GYCTF2020]EasyThinking --不会编程的崽

看标题就知道&#xff0c;这大概率是关于thinkphp的题目。先尝试错误目录使其报错查看版本号 thinkphp v6.0.0&#xff0c;在网上搜索一下&#xff0c;这个版本有一个任意文件上传漏洞。参考以下文章。 https://blog.csdn.net/god_zzZ/article/details/104275241 先注册一个账…

【Android】位置修改相关

获取位置服务总开关状态 //获取LOCATION_MODE值&#xff0c;但adb状态下无法获取 //0为关闭&#xff0c;1 gps、2 network、3 高精度等 int state Settings.Secure.getInt(mContext.getContentResolver(),Settings.Secure.LOCATION_MODE,Settings.Secure.LOCATION_MODE_HIGH_…

three.js可以对3D模型做什么操作和交互,这里告诉你。

Three.js 提供了多种交互功能&#xff0c;可以对 3D 模型进行各种操作和交互。以下是一些常见的交互功能&#xff1a; 鼠标交互 通过鼠标事件&#xff0c;可以实现模型的拖拽、旋转、缩放等操作。例如&#xff0c;可以通过鼠标拖拽来改变模型的位置或角度。 触摸交互 对于支…

PackagesNotFoundError:学习利用报错信息找到解决方法

反思&#xff1a;之前看到报错经常是直接复制报错信息去网上搜&#xff0c;但很多情况下报错信息里其实就给出了解决方案 报错信息&#xff1a; Collecting package metadata (current_repodata.json): done Solving environment: unsuccessful initial attempt using frozen …

MySQL 篇-深入了解多表设计、多表查询

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 多表设计概述 1.1 多表设计 - 一对多 1.2 多表设计 - 一对一 1.3 多表设计 - 多对多 2.0 多表查询概述 2.1 多表查询 - 内连接 2.2 多表查询 - 外连接 2.3 多表查…

cetos7 Docker 安装 gitlab

一、gitlab 简单介绍和安装要求 官方文档&#xff1a;https://docs.gitlab.cn/jh/install/docker.html 1.1、gitlab 介绍 gitLab 是一个用于代码仓库管理系统的开源项目&#xff0c;使用git作为代码管理工具&#xff0c;并在此基础上搭建起来的Web服务平台&#xff0c;通过该平…

【C语言】指针初阶2.0版本

这篇博文我们来继续学习指针的其他内容 指针2.0 传值调用与传址调用传值调用传址调用 一维数组与指针理解数组名使用指针深入理解一维数组 二级指针指针数组二维数组与指针 传值调用与传址调用 在开始之前&#xff0c;我们需要先了解这个概念&#xff0c;后面才能够正常的学习…

Material UI 5 学习01-按钮组件

Material UI 5 学习01-按钮组件 一、安装Material UI二、 组件1、Button组件1、基础按钮2、variant属性3、禁用按钮4、可跳转的按钮5、disableElevation属性6、按钮的点击事件onClick 2、Button按钮的颜色和尺寸1、Button按钮的颜色2、按钮自定义颜色3、Button按钮的尺寸 3、图…

vulhub中ThinkPHP5 SQL注入漏洞 敏感信息泄露

漏洞原理 传入的某参数在绑定编译指令的时候又没有安全处理&#xff0c;预编译的时候导致SQL异常报错。然而thinkphp5默认开启debug模式&#xff0c;在漏洞环境下构造错误的SQL语法会泄漏数据库账户和密码 启动后&#xff0c;访问http://your-ip/index.php?ids[]1&ids[]2…

nodejs安装教程(及过程中的易错)

nodejs&#xff1a;Nodejs 是基于 Chrome 的 V8 引擎开发的一个 C 程序&#xff0c;目的是提供一个 JS 的运行环境。 npm&#xff1a;npm 是 Node Package Manager 的缩写&#xff0c;意思是 Node 的包管理系统&#xff0c;是最大的软件包仓库 下载nodejs 首先我们需要在node…

智慧城市中的数据力量:大数据与AI的应用

目录 一、引言 二、大数据与AI技术的融合 三、大数据与AI在智慧城市中的应用 1、智慧交通 2、智慧环保 3、智慧公共安全 4、智慧公共服务 四、大数据与AI在智慧城市中的价值 1、提高城市管理的效率和水平 2、优化城市资源的配置和利用 3、提升市民的生活质量和幸福感…

去除PDF论文行号的完美解决方案

去除PDF论文行号的完美解决方案 1. 遇到的问题 我想去除论文的行号&#xff0c;但是使用网上的Adobe Acrobat裁剪保存后 如何去掉pdf的行编号&#xff1f; - 知乎 (zhihu.com) 翻译时依然会出现行号&#xff0c;或者是转成word&#xff0c;这样就大大损失了格式&#xff0c…

C语言结构体的大小,结构体内存对齐

1. 结构体的大小 在自己正真了解过之前&#xff0c;一直认为结构体的大小就是结构体内部成员大小的总和。 但当你去尝试打印结构体的大小时&#xff0c;会发现事实并非如此&#xff0c;也不会像你想的那样简单。 #include <stdio.h>struct S1 {char c1;char c2;int i;…

springcloud:3.7测试线程池服务隔离

服务提供者【test-provider8001】 Openfeign远程调用服务提供者搭建 文章地址http://t.csdnimg.cn/06iz8 相关接口 测试远程调用&#xff1a;http://localhost:8001/payment/index 服务消费者【test-consumer-resilience4j8004】 Openfeign远程调用消费者搭建 文章地址http://t…

人工智能指数报告2023

人工智能指数报告2023 主要要点第 1 章 研究与开发第 2 章 技术性能第 3 章 人工智能技术伦理第 4 章 经济第 5 章 教育第 6 章 政策与治理第 7 章 多样性第 8 章 舆论 人工智能指数是斯坦福大学以人为本的人工智能研究所&#xff08;HAI&#xff09;的一项独立倡议&#xff0c…

如何编写自动化测试用例?

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 自动化测试脚本 什么是自动化测试&#xff1f; 自动化测试是验…

go并发模式之----工作池/协程池模式

常见模式之四&#xff1a;工作池/协程池模式 定义 顾名思义&#xff0c;就是有固定数量的工人&#xff08;协程&#xff09;&#xff0c;去执行批量的任务 使用场景 适用于需要限制并发执行任务数量的情况 创建一个固定大小的 goroutine 池&#xff0c;将任务分发给池中的 g…

Vue.js+SpringBoot开发森林火灾预警系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 系统基础模块2.3 烟雾传感器模块2.4 温度传感器模块2.5 历史记录模块2.6 园区数据模块 三、系统设计3.1 用例设计3.1.1 森林园区基础系统用例设计3.1.2 森林预警数据用例设计 3.2 数据库设计3.2.1 烟雾…

Linux 之二:CentOS7 的 IP 常用命令和配置及 xshell 基本使用方法

1. 进入虚拟机 点击右键---进入终端--输入 ip adrr 或 ifconfig 查看ip地址 下面输入命令 ifconfig&#xff08;注意&#xff1a;不是 ipconfig &#xff09; 或 ip addr 来查看当前系统 IP 查看到IP 后&#xff0c;比如&#xff1a;上面是 192.168.184.137 1.1 IP 常用命令…