目录
一,题目描述
英文描述
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called root.
Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that all houses in this place form a binary tree. It will automatically contact the police if two directly-linked houses were broken into on the same night.
Given the root of the binary tree, return the maximum amount of money the thief can rob without alerting the police.
中文描述
小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。
除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。
给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。
示例与说明
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/house-robber-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二,解题思路
参考官方题解@力扣官方题解【打家劫舍 III】
后序遍历+动态规划,后序遍历指明了动态规划的转移顺序。
声明一个长度为2的数组记录动态规划过程中产生的值,其中位置0表示不选择当前节点,1表示选择当前节点;
先遍历左子树得到左子树的状态数组leftTree,再遍历右子树得到右子树的状态数组rightTree,最后可以得到当前节点的状态数组ans
不选当前节点,左右子树节点可选可不选(取两种方案最大值):
- ans[0] = Math.max(leftTree[0], leftTree[1]) + Math.max(rightTree[0], rightTree[1])
选择当前节点,左右两子节点均不能选择:
- ans[1] = root.val + leftTree[0] + rightTree[0]
三,AC代码
Java
class Solution {
public int rob(TreeNode root) {
int[] ans = dfs(root);
return Math.max(ans[0], ans[1]);
}
public int[] dfs(TreeNode root) {
if (root == null) return new int[]{0, 0};
int[] leftTree = dfs(root.left);
int[] rightTree = dfs(root.right);
int[] ans = new int[2];
ans[1] = root.val + leftTree[0] + rightTree[0];// 选择root节点,则左右子树节点不能被选中
ans[0] = Math.max(leftTree[0], leftTree[1]) + Math.max(rightTree[0], rightTree[1]);// 不选root节点,左右子树节点可选可不选(取两种方案最大值)
return ans;
}
}
四,解题过程
第一搏
后序遍历 + 双hash表(分别记录是否选择当前节点下的情况)
class Solution {
Map<TreeNode, Integer> choose = new HashMap<>();
Map<TreeNode, Integer> notChoose = new HashMap<>();
public int rob(TreeNode root) {
choose.put(null, 0);
notChoose.put(null, 0);
dfs(root);
return Math.max(choose.get(root), notChoose.get(root));
}
public void dfs(TreeNode root) {
if (root == null) return;
dfs(root.left);
dfs(root.right);
int ans = 0;
ans = root.val + notChoose.get(root.left) + notChoose.get(root.right);
choose.put(root, ans);
int maxLeft = Math.max(choose.get(root.left), notChoose.get(root.left));
int maxRight = Math.max(choose.get(root.right), notChoose.get(root.right));
ans = maxLeft + maxRight;
notChoose.put(root, ans);
}
}
第二搏
注意到后序遍历过程中,只会用到当前节点左右两子树节点对应的状态,因此递归返回值可以用大小为2的数组代替,其中位置0表示不选择当前节点,1表示选择当前节点。
这样递归过程将会变得更加简洁