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

news2024/11/16 4:29:05

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 defaultdict
        dp_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.left
            right=now.right

            res1=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]=res2

            return 
        
        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_rob
        return max(travel_tree(root))  # 根节点选或不选的最大值

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

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

相关文章

使用query请求数据出现500的报错

我在写项目的时候遇到了一个问题,就是在存商品id的时候我将它使用了JSON.stringify的格式转换了!!!于是便爆出了500这个错误!!! 我将JSON.stringify的格式去除之后,它就正常显示了&…

Linux - 进程控制

1、进程创建 1.1、fork函数初识 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程&#xff1b; #include <unistd.h> pid_t fork(void); 返回值&#xff1a;自进程中返回0&#xff0c;父进…

java常见的8种数据结构

一、线性结构&#xff1a;数组、链表、哈希表&#xff1b;队列、栈 1.数组&#xff1a; 数组是有序元素的序列&#xff0c;在内存中的分配是连续的&#xff0c;数组会为存储的元素都分配一个下标&#xff08;索引&#xff09;&#xff0c;此下标是一个自增连续的&#xff0c;访…

万村乐数字乡村系统开源代码:革命性引领,助推乡村振兴新篇章

如今&#xff0c;国际社会普遍认为信息化、数字化已是重大且不可逆转的发展趋势&#xff0c;如何让广大农村地区充分分享到这个发展带来的红利&#xff0c;从而提升农村的经济活力&#xff0c;确保村民生活质量不断优化&#xff0c;已然成为我们需要认真研究并积极解决的重大议…

美国法院命令NSO集团将其间谍软件代码交给WhatsApp

Techreport网站消息&#xff0c;近日&#xff0c;美国法院下令要求以色列间谍软件开发商NSO集团将其Pegasus间谍软件的代码交给WhatsApp。 2019年&#xff0c;NSO集团利用WhatsApp的安全漏洞对1400名用户进行了为期两周的监视。同年&#xff0c;WhatsApp向该公司提起了法律诉讼…

k8s初始化错误

报错详情&#xff1a; you can check the kubelet logs for further clues by running: ‘journalctl -u kubelet’ Alternatively, there might be issues with your Kubernetes configuration files or maybe the necessary ports are not opened. Check the status of …

应用方案丨D317大电流可调稳压电路

1、 概述&#xff1a; D317是一款三端可调正稳压器集成电路&#xff0c;其输出电压范围是1.2V至37V&#xff0c;负载电流最大为1.5A。它的使用非常简单&#xff0c;仅需两个外接电阻来设置输出电压。此外&#xff0c;它的电压线性度和负载调整率也比标准的固定稳压器好。D317内…

通过联合部署DDoS高防和WAF提升网站防护能力

如果您的网站遭受的攻击既有流量型攻击&#xff0c;又混杂精巧的Web应用层攻击时&#xff08;例如SQL注入、跨站脚本攻击、命令注入等&#xff09;时&#xff0c;推荐您组合使用阿里云DDoS高防和Web 应用防火墙 WAF&#xff08;Web Application Firewall&#xff09;&#xff0…

【MySQL】事务管理 -- 详解

一、前言 CURD 不加控制&#xff0c;会有什么问题&#xff1f; CURD 满足什么属性&#xff0c;能解决上述问题&#xff1f; 买票的过程得是原子的。买票应该不能受互相的影响。买完票应该要永久有效。买前和买后都要是确定的状态。 什么是事务&#xff1f; 事务就是一组 DML…

2024-03-03 c++

&#x1f338; MFC进度条控件 | Progress Control 1。新建MFC项目&#xff08;基于对话框、静态库&#xff09; 2。添加控件&#xff0c;删除初始的3个多余控件 加1个progress control&#xff0c;修改其marquee为true&#xff0c;添加变量&#xff1a;变量名为test_progress。…

乡村教师的待遇会比城里的好吗

每次提到乡村教师&#xff0c;我们总会联想到那些坚守在偏远山区的教育工作者&#xff0c;他们默默无闻&#xff0c;为了乡村的孩子们奉献着自己的青春和热血。那么&#xff0c;乡村教师的待遇究竟如何呢&#xff1f;是否真的如外界所传闻的那般&#xff0c;比城里的教师还要好…

ip https证书360元买一年送一月

随着互联网的发展&#xff0c;不论是用户还是开发者&#xff0c;都越来越重视互联网环境的安全性。IP https证书是一种网络安全协议&#xff0c;用于保护网络通信的安全性和机密性。IP https数字证书是CA认证机构为只有公网IP地址&#xff0c;没有域名的站点颁发的数字证书&…

华为HarmnyOS TypeScript基础语法快速入门

华为HarmnyOS TypeScript基础语法快速入门 一、JavaScript、TypeScript、ArkTS二、TypeScript基础语法1. 基础类型2. 条件语句3. 函数4. 类5. 模块6. 迭代器 一、JavaScript、TypeScript、ArkTS ArkTS是HarmonyOS优选的主力应用开发语言。它在TypeScript&#xff08;简称TS&am…

信钰证券:四川黄金超50亿元解禁,紫金矿业等解禁股东浮盈超200%

本周A股限售股解禁规划不到400亿元&#xff0c;环比下降。 除掉新上市公司&#xff0c;本周共有43家公司限售股解禁&#xff0c;解禁数量28.91亿股&#xff0c;以最新收盘价计算&#xff08;下同&#xff09;&#xff0c;解禁市值387.66亿元。 其间&#xff0c;解禁市值超越1…

MASS/MM17批量复制物料描述

需求&#xff1a; 批量将日文环境中的物料描述复制到英文环境。 实现&#xff1a; 1.将日文环境下的物料描述下载至本地excel。 2.新建EXCEL&#xff0c;添加如下标题列&#xff0c;并将第一步下载下来的内容粘贴至对应的列&#xff0c;MANDT改为实际要更新的客户端&#xf…

基于Python的单词抽取测试工具

一、引言 在语言学习的过程中&#xff0c;单词量的多少是衡量一个人英语水平的重要指标。而如何快速扩充词汇量&#xff0c;掌握单词的汉语意思是重多师生的痛点和难点。为了帮助学习者有效地扩展词汇&#xff0c;巩固学习成果&#xff0c;我们在ChatGPT-4.0的帮助下&#xff…

Cookie和session 及Web相关工具

一 Cookie &#xff08;一&#xff09;介绍 Cookie 又称为"小甜饼”。类型为"小型文本文件”&#xff0c;指某些网站为了辨别用户身份而储存在用户本地终端&#xff08;Client Side&#xff09;上的数据&#xff08;通常经过加密&#xff09;。由网景公司的前雇员…

深入了解 Android 中的 FrameLayout 布局

FrameLayout 是 Android 中常用的布局之一&#xff0c;它允许子视图堆叠在一起&#xff0c;可以在不同位置放置子视图。在这篇博客中&#xff0c;我们将详细介绍 FrameLayout 的属性及其作用。 <FrameLayout xmlns:android"http://schemas.android.com/apk/res/androi…

机器学习-面经(part4、决策树)

7. 决策树 7.1 ID算法 核心是在决策树各个节点上应用信息增益准则选择特征,递归的构建决策树。 具体方法是:从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点;再对子结点递归的调用以上方法,构建…