一天一大 lee(打家劫舍 III)难度:中等-Day20200805
时间:2022-07-25
本文章向大家介绍一天一大 lee(打家劫舍 III)难度:中等-Day20200805,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目:
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
示例
- 示例 1
输入: [3,2,3,null,3,null,1]
3
/
2 3
3 1
输出: 7
解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.
- 示例 2
输入: [3,4,5,1,3,null,1]
3
/
4 5
/
1 3 1
输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.
抛砖引玉
抛砖引玉
思路
- 已知相连的节点不能累加,则任意选一个节点就能将树分成两组,包含这个节点的不包含这个节点
- 用 dpRoot 保存包含这个节点的结果
- dp 存贮不包含这个节点的结果
设节点 node:
- 包含 node,dpRoot[node]应该等于这个节点的值+相邻节点不被包含着的值 dpRoot[node] = node.val+dp[node.left]+dp[node.right]
- 不包含 node,则 node.left 与 node.right 不受限,可以任选包含或者不被包含,取可能的最大值:
- dpRootLeft[node.left]、dp[node.left]
- dpRootLeft[node.right]、dp[node.right]
特殊条件及递归终止条件
- root 伪 null 返回 0
- 递归至最后一层节点 null,终止递归
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var rob = function (root) {
if (root === null) return 0
// 二叉树中节点值可能重复,则使用map记录节点位置
let dpRoot = new Map(), // 包含key对应的节点
dp = new Map() // 不包含key对应的节点
function dfs(node) {
// 递归终止
if (node === null) return 0
// 递归枚举包含node.left的情况
dfs(node.left)
// 递归枚举包含node.right的情况
dfs(node.right)
let dpRootLeft = dpRoot.get(node.left) || 0,
dpRootRight = dpRoot.get(node.right) || 0,
dpLeft = dp.get(node.left) || 0,
dpRight = dp.get(node.right) || 0
// 包含传入节点这
dpRoot.set(node, node.val + dpLeft + dpRight)
// 选不包含传入节点
dp.set(node, Math.max(dpRootLeft, dpLeft) + Math.max(dpRootRight, dpRight))
}
// 递归枚举包含根据点的情况
dfs(root)
return Math.max(dpRoot.get(root), dp.get(root))
}
- 因为 dpRoot 与 dp 计算时都值依赖那相邻节点的值
- 则可以再递归中返回需要相邻的包含、不包含的两种可能
/**
* @param {TreeNode} root
* @return {number}
*/
var rob = function (root) {
let [dpRoot, dp] = dfs(root)
function dfs(root) {
if (root === null) return [0, 0]
// 枚举分别包含左右节点的情况
let [dpRootLeft, dpLeft] = dfs(root.left),
[dpRootRight, dpRight] = dfs(root.right)
let dpRoot = root.val + dpLeft + dpRight,
dp = Math.max(dpRootLeft, dpLeft) + Math.max(dpRootRight, dpRight)
return [dpRoot, dp]
}
return Math.max(dpRoot, dp)
}
- 不相邻节点累加,即node.val与node.left、node.right不同组
- 递归调用rob,返回包含输入节点、不包含输入点的和最大值
/**
* @param {TreeNode} root
* @return {number}
*/
var rob = function (root) {
// 递归终止条件
if (root == null) return 0
let Root = 0,// 包含根节点
noRoot = 0 // 不包含根节点
// 累加存在的不相邻节点
let Root = root.val
if (root.left) {
Root += rob(root.left.left) + rob(root.left.right)
}
if (root.right) {
Root += rob(root.right.left) + rob(root.right.right)
}
// 不包含根节点节点累加
let noRoot = rob(root.left) + rob(root.right)
return Math.max(Root, noRoot)
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Spring全家桶之SpringData——SpringData Redis(附相关jar包)
- Spring全家桶之SpringBoot——初级阶段
- Spring全家桶之SpringBoot——高级阶段
- feign.FeignException$MethodNotAllowed: status 405 reading xxx#yyy(Integer)
- No serializer found for class 类名 and no properties discovered to create BeanSerializer
- 三步让你在Linux中发布SpringCloud项目
- 【赵渝强老师】MySQL高可用架构:MHA
- Python终极调试指南
- Spring全家桶之SpringCloud——高级阶段(上)
- go实现利用最大堆寻找最小k个数
- Go实现字符串相乘无溢出最详细解释
- 寻找和为定值的两个数
- 还不会命令行?用Go Flag自写命令行程序
- 【go】剑指offer:常见排序算法
- 剑指offer:重建一个二叉树