Skip to main content

打家劫舍-iii

Tips

题目类型: Dynamic Programming

相关题目:

题目

小偷又发现了一个新的可行窃的地区. 这个地区只有一个入口, 我们称之为 root.

除了 root 之外, 每栋房子有且只有一个"父"房子与之相连. 一番侦察之后, 聪明的小偷意识到"这个地方的所有房屋的排列类似于一棵二叉树". 如果 两个直接相连的房子在同一天晚上被打劫, 房屋将自动报警.

给定二叉树的 root. 返回在不触动警报的情况下, 小偷能够盗取的最高金额.

提示:
  • 树的节点数在 [1, 10⁴] 范围内
  • 0 <= Node.val <= 10⁴
示例

337-rob-1

输入: root = [3,2,3,null,3,null,1]
输出: 7
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7

337-rob-2

输入: root = [3,4,5,1,3,null,1]
输出: 9
解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9

题解

核心点要用后序遍历, 然后和前两个题一样, 如果抢了当前节点, 两个孩子就不能抢了; 如果没抢当前节点, 就可以考虑抢左右孩子.

/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var rob = function (root) {
const dfs = (node) => {
// 用一个数组表示强和不抢: 其中第一个元素代表抢; 第二个元素代表不抢
if (!node) return [0, 0]

const left = dfs(node.left)
const right = dfs(node.right)
const rob = node.val + left[1] + right[1] // 抢当前节点, 意味着左右子节点不可抢
const notRob = Math.max(left[0], left[1]) + Math.max(right[0], right[1]) // 当前不抢, 左右子节点可以考虑抢或不抢
return [rob, notRob]
}

return Math.max(...dfs(root))
}