打家劫舍Ⅱ:leetcode-337

95 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第23天,点击查看活动详情

打家劫舍Ⅱ

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

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

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

示例

  • 示例1
输入:
      3
  2      3
    3      1
输出:3 + 3 + 1 = 7(偷第一层和第三层)
  • 示例2
输入:
      3
  4      5
1   3      1
输出:4 + 5 = 9(只偷第二层)

代码实现

看到树,就一定会想到递归,这道题目还多了个条件(是否选择,也就是偷还是不偷)

  • 在递归过程中,如果选择当前节点,则结果为当前节点的value 加上左右子节点的不选择值
  • 如果没选择当前节点,则结果为左边叶子节点的最大值(选中、不选中)加上右边叶子节点的最大值(选中、不选中)
var rob = function(root) {
  const rootValue = dfs(root) // 返回一个数组,数组中只有两个元素:左边的为“选择当前节点的值”,右边的为“不选择当前节点的值”
  return Math.max(...rootValue) // 返回较大的一个
}
function dfs(node) {
  if(!node) return [0, 0]
  const l = dfs(node.left) // 获取左子节点的最大值(也是一个拥有两个元素的数组)
  const r = dfs(node.right) // 同理,获取右子节点的最大值
  
  // 下面判断是否选择当前节点(是否要偷当前房屋)
  
  // 如果偷的话,就加上当前节点的值(node.val),然后两个子节点是一定不能偷的,所以使用 l 和 r 的第二个元素  
  const selected = node.val + l[1] + r[1]; 
  // 如果不偷的话,就拿到左子节点的最大值和右子节点的最大值,让其相加
  const noSelected = Math.max(...l) + Math.max(...r)
  return [selected, noSelected]
}