题目
一个二叉树,每个节点上都有权值,当父节点和子节点不能同时选中的前提下,二叉树的最大值
实例请看 :https://leetcode-cn.com/problems/house-robber-iii/
解析
每个节点有两种状态
- 已选中当前节点的情况下,当前节点从下往上的最大权值。
- 未选中当前节点的情况下,当前节点从下往上的最大权值。
存储每个节点的两种状态
- 定义两个哈希表,Key为节点,value为最大权值。
- 第一个哈希表存已选中的情况下的每个节点的最大权值
- 第二个哈希表存未选中的情况下的每个节点的最大权值
如何计算?
- 当节点是叶子节点时,选中情况下的最大权值即本身的值,未选中情况下的最大权值即是0
- 当节点不是叶子节点时
①:已选中情况下的最大权值即 子节点都不能选中的最大值加上自己本身的值。
②:未选中的情况,子节点可以是选中状态,也可以是不选中的状态,所以取子节点的选中和不选中的状态里的最大值,加起来即可。
采用算法?
- 采用哈希表存两种不同状态下的最大权值即是动态规划里的子问题重复使用的思想
- 在 “ 如何计算?” 一节里,分析了父节点与子节点的关系计即是动态规划里的状态转移方程式
- 如下:(实际应用时需要判null)
child_left_max = max(left_child_select,left_child_no_select)
child_right_max = max(right_child_select,right_child_no_select)
parent = max(child_left_max,child_right_max)
附上代码:
public int rob(TreeNode root) {
if(root == null){
return 0;
}
// 定义一个HashMap 存储每个节点 盗窃的最优解
Map<TreeNode,Integer> result = new HashMap<>();
// 定义一个HashMap 储存每个节点 不盗窃的最优解
Map<TreeNode,Integer> result1 = new HashMap<>();
Stack<TreeNode> stack = new Stack<>();
Stack<TreeNode> stack1 = new Stack<>();
stack.add(root);
stack1.add(root);
while(!stack.isEmpty()){
TreeNode pop = stack.pop();
if(pop.left != null){
stack.add(pop.left);
stack1.add(pop.left);
}
if(pop.right != null){
stack.add(pop.right);
stack1.add(pop.right);
}
}
while(!stack1.isEmpty()){
TreeNode pop = stack1.pop();
// 当 当前节点盗窃的情况下,最优解
// 当前节点盗窃 所以子节点都只能不盗窃 所以 左右节点的不盗窃最优解加上当前节点的值,
result.put(pop,(pop.left == null ? 0:result1.get(pop.left)) + (pop.right == null ? 0:result1.get(pop.right)) + pop.val);
// 当 当前节点不盗窃下的最优解
// 左右的节点都可以是盗窃和不盗窃
int leftMax = 0;
if(pop.left != null){
leftMax = Math.max(result.get(pop.left),result1.get(pop.left));
}
int rightMax = 0;
if(pop.right != null){
rightMax = Math.max(result.get(pop.right),result1.get(pop.right));
}
result1.put(pop,leftMax + rightMax);
}
return Math.max(result.get(root),result1.get(root));
}