[Leetcode][第337题][JAVA][打家劫舍3][递归][动态规划]

【问题描述】[中等]

在这里插入图片描述

【解答思路】

1. 动态规划

第 1 步:状态定义
dp[node][j] :这里 node 表示一个结点,以 node 为根结点的树,并且规定了 node 是否偷取能够获得的最大价值。

j = 0 表示 node 结点不偷取;
j = 1 表示 node 结点偷取。
第 2 步: 推导状态转移方程
根据当前结点偷或者不偷,就决定了需要从哪些子结点里的对应的状态转移过来。

如果当前结点不偷,左右子结点偷或者不偷都行,选最大者;
如果当前结点偷,左右子结点均不能偷。
(状态转移方程的表述有点复杂,请大家直接看代码。)

第 3 步: 初始化
一个结点都没有,空节点,返回 0,对应后序遍历时候的递归终止条件;

第 4 步: 输出
在根结点的时候,返回两个状态的较大者。

第 5 步: 思考优化空间
优化不了。
时间复杂度:O(N) 空间复杂度:O(N)

public class Solution {// 树的后序遍历public int rob(TreeNode root) {int[] res = dfs(root);return Math.max(res[0], res[1]);}private int[] dfs(TreeNode node) {if (node == null) {return new int[]{0, 0};}// 分类讨论的标准是:当前结点偷或者不偷// 由于需要后序遍历,所以先计算左右子结点,然后计算当前结点的状态值int[] left = dfs(node.left);int[] right = dfs(node.right);// dp[0]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点不偷// dp[1]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点偷int[] dp = new int[2];dp[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);dp[1] = node.val + left[0] + right[0];return dp;}
}
2. 递归

使用爷爷、两个孩子、4 个孙子来说明问题
首先来定义这个问题的状态
爷爷节点获取到最大的偷取的钱数呢

  1. 首先要明确相邻的节点不能偷,也就是爷爷选择偷,儿子就不能偷了,但是孙子可以偷
  2. 二叉树只有左右两个孩子,一个爷爷最多 2 个儿子,4 个孙子
    根据以上条件,我们可以得出单个节点的钱该怎么算
    4 个孙子偷的钱 + 爷爷的钱 VS 两个儿子偷的钱 哪个组合钱多,就当做当前节点能偷的最大钱数。这就是动态规划里面的最优子结构
    由于是二叉树,这里可以选择计算所有子节点

4 个孙子投的钱加上爷爷的钱如下
int method1 = root.val + rob(root.left.left) + rob(root.left.right) + rob(root.right.left) + rob(root.right.right)
两个儿子偷的钱如下
int method2 = rob(root.left) + rob(root.right);
挑选一个钱数多的方案则
int result = Math.max(method1, method2);

2.1暴力递归

public int rob(TreeNode root) {if (root == null) return 0;int money = root.val;if (root.left != null) {money += (rob(root.left.left) + rob(root.left.right));}if (root.right != null) {money += (rob(root.right.left) + rob(root.right.right));}return Math.max(money, rob(root.left) + rob(root.right));
}

2.2 记忆化递归
针对2.1中速度太慢的问题,经过分析其实现,我们发现爷爷在计算自己能偷多少钱的时候,同时计算了 4 个孙子能偷多少钱,也计算了 2 个儿子能偷多少钱。这样在儿子当爷爷时,就会产生重复计算一遍孙子节点。

于是乎我们发现了一个动态规划的关键优化点

我们这一步针对重复子问题进行优化,我们在做斐波那契数列时,使用的优化方案是记忆化,但是之前的问题都是使用数组解决的,把每次计算的结果都存起来,下次如果再来计算,就从缓存中取,不再计算了,这样就保证每个数字只计算一次。
由于二叉树不适合拿数组当缓存,我们这次使用哈希表来存储结果,TreeNode 当做 key,能偷的钱当做 value

public int rob(TreeNode root) {
//hashmap 记忆化HashMap<TreeNode, Integer> memo = new HashMap<>();return robInternal(root, memo);
}public int robInternal(TreeNode root, HashMap<TreeNode, Integer> memo) {if (root == null) return 0;if (memo.containsKey(root)) return memo.get(root);int money = root.val;if (root.left != null) {money += (robInternal(root.left.left, memo) + robInternal(root.left.right, memo));}if (root.right != null) {money += (robInternal(root.right.left, memo) + robInternal(root.right.right, memo));}int result = Math.max(money, robInternal(root.left, memo) + robInternal(root.right, memo));///!!!memo.put(root, result);return result;
}

【总结】

1. 动态规划流程

第 1 步:设计状态
第 2 步:状态转移方程
第 3 步:考虑初始化
第 4 步:考虑输出
第 5 步:考虑是否可以状态压缩

2.递归 递推公式要找准 后用记忆化搜索优化 这题不能用BFS,层次遍历不符合题解

转载链接:https://leetcode-cn.com/problems/house-robber-iii/solution/san-chong-fang-fa-jie-jue-shu-xing-dong-tai-gui-hu/
转载链接:https://leetcode-cn.com/problems/house-robber-iii/solution/shu-xing-dp-ru-men-wen-ti-by-liweiwei1419/

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

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

相关文章

什么是压缩感知?[简单概括]

什么是压缩感知&#xff1f; 压缩感知(compressive sensing)有两部分组成 感知(sensing):所谓感知就是站在计算机角度上&#xff0c;我们作为计算机感知一种信号&#xff08;图片&#xff09;&#xff0c;也就是计算机去理解这种信号的一种拟人化的描述&#xff0c;比如10010…

依赖注入模式中,为什么用对象而不是用数组传递?

依赖注入&#xff08;Dependence Injection, DI&#xff09; 依赖注入是控制反转的一种设计模式。依赖注入的核心是把类所依赖的单元的实例化过程&#xff0c;放到类的外面去实现。依赖注入的实现离不开反射。 依赖注入&#xff08;Dependence Injection, DI&#xff09; 所谓的…

【数据结构与算法】递归

一、什么是递归&#xff1f; 1.递归是一种非常高效、简洁的编码技巧&#xff0c;一种应用非常广泛的算法&#xff0c;比如DFS深度优先搜索、前中后序二叉树遍历等都是使用递归。 2.方法或函数调用自身的方式称为递归调用&#xff0c;调用称为递&#xff0c;返回称为归。 二、…

二元随机变量函数的分布

在前面的文章记录了二元随机变量的定义、离散型二元随机变量的联合分布律/联合概率密度函数、边际分布律/边际概率密度函数、条件分布律/条件概率密度 &#xff0c;以及对应的 联合分布函数、边际分布函数、条件分布函数。这篇文档介绍二元随机变量函数的分布。 二元随机变量函…

力扣 1553. 吃掉 N 个橘子的最少天数 记忆化DFS|记忆化BFS|剪枝

吃掉 N 个橘子的最少天数 厨房里总共有 n 个橘子&#xff0c;你决定每一天选择如下方式之一吃这些橘子&#xff1a; 吃掉一个橘子。 如果剩余橘子数 n 能被 2 整除&#xff0c;那么你可以吃掉 n/2 个橘子。 如果剩余橘子数 n 能被 3 整除&#xff0c;那么你可以吃掉 2*(n/3) 个…

spring容器bean的作用域 spring容器是否是单例的一些问题

Spring容器中Bean的作用域 当通过Spring容器创建一个Bean实例时&#xff0c;不仅可以完成Bean实例的实例化&#xff0c;还可以为Bean指定特定的作用域。Spring支持如下5种作用域&#xff1a; singleton&#xff1a;单例模式&#xff0c;在整个Spring IoC容器中&#xff0c;使用…

第四十期:2019年度十大Web开发趋势

本文和您一起讨论那些本年度改变软件开发行业、特别是Web开发方面的十大趋势。 如今&#xff0c;随着各种新趋势的层出不穷&#xff0c;Web和移动领域的创新不仅改变了人们、乃至整个社会的日常行为习惯、以及业务处理方式&#xff0c;而且也使得开发人员能够轻松、且高效地创建…

【数据结构与算法】排序 冒泡、插入、选择 O(n^2)

冒泡、插入、选择 O(n2) 基于比较 快排、归并 O(nlogn) 基于比较 计数、基数、桶 O(n) 不基于比较 一、如何分析一个排序算法&#xff1f; 学习排序算法的思路&#xff1f;明确原理、掌握实现以及分析性能。如何分析排序算法性能&#xff1f;从执行效率、内存消耗以及稳定性…

第一单元:微积分

打算写一下微积分的笔记。以供日后复习。学习来源是网易公开课的麻省理工大学的单变量微积分。下载了MIT官网的课堂笔记。 第一单元概览 1 微积分、斜率、速度、和变化率(derivatives,slop,velocity and rate of change) 2 极限、连续性、三角函数的极限(Limits,continuity …

题解 P5301 【[GXOI/GZOI2019]宝牌一大堆】

这道题除了非常恶心以外也没有什么非常让人恶心的地方 当然一定要说有的话还是有的&#xff0c;就是这题和咱 ZJOI 的 mahjong 真的是好像的说~ 于是就想说这道题出题人应该被 锕 掉 noteskey 整体的思路就是特判国士无双和七对子&#xff0c;然后 dp 搞普通的胡牌 dp 状态设计…

力扣:组合总和 II DFS剪枝

组合总和 II 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 说明&#xff1a; 所有数字&#xff08;包括目标数&#xff09;都是正整数。 解集不能包…

[Leetcode][第336题][JAVA][回文对][暴力][HashSet][字典树]

【问题描述】[困难] 【解答思路】 1. 暴力&#xff08;超时&#xff09; 时间复杂度&#xff1a;O(n 2 m)&#xff0c;其中 n 是字符串的数量&#xff0c;m 是字符串的平均长度 空间复杂度&#xff1a;O(1) class Solution {public List<List<Integer>> palindr…

第十二期:面试官问你什么是消息队列?把这篇甩给他!

消息队列不知道大家看到这个词的时候&#xff0c;会不会觉得它是一个比较高端的技术&#xff0c;反正我是觉得它好像是挺牛逼的。 一、什么是消息队列&#xff1f; 消息队列不知道大家看到这个词的时候&#xff0c;会不会觉得它是一个比较高端的技术&#xff0c;反正我是觉得它…

第三章 随机变量的数字特征

数学期望 数学期望用来反映平均情况。 定义 设离散型随机变量X的分布律为P(Xxk)pk,k1,2,3...&#xff0c;若级数∑∞k1xkpk是收敛的&#xff0c;则称级数∑∞k1xkpk的值为随机变量X的数学期望。记为E(X)。E(X)∑k1∞xkpkpk可以理解为加权平均中的权值。数学期望又称为 均值。 …

python二进制、字符编码及文件操作

1. 二进制 bin()十进制转二进制 0b oct&#xff08;&#xff09;十进制转八进制 0o hex&#xff08;&#xff09;十进制转十六进制 0x&#xff0c;4个二进制对应1个16进制&#xff0c;用于网络编程&#xff0c;数据存储 print(int(110111,2)) 55 print(int(ffff,16)) 65535 p…

【数据结构与算法】【字符串匹配】Trie树

单模式串匹配 BF 算法和 RK 算法 BM 算法和 KMP 算法多模式串匹配算法 Trie 树和 AC 自动机 一、 什么是“Trie树”&#xff1f; 1. 他是一种树形结构&#xff0c;是一种专门处理字符串匹配的数据结构&#xff0c;解决在一组字符串集合中快速查找某个字符串的问题。 2. Trie…

第十三期:消灭 Java 代码的“坏味道”

代码中的"坏味道"&#xff0c;如"私欲"如"灰尘"&#xff0c;每天都在增加&#xff0c;一日不去清除&#xff0c;便会越累越多。如果用功去清除这些"坏味道"&#xff0c;不仅能提高自己的编码水平&#xff0c;也能使代码变得"精白…

力扣 两数相加 指针操作注意事项

两数相加 给出两个 非空 的链表用来表示两个非负的整数。其中&#xff0c;它们各自的位数是按照 逆序 的方式存储的&#xff0c;并且它们的每个节点只能存储 一位 数字。 如果&#xff0c;我们将这两个数相加起来&#xff0c;则会返回一个新的链表来表示它们的和。 您可以假设…