一个很有意思的问题,一个社区,所有的房子构成一棵二叉树,每个房子里有一定价值的财物,这棵二叉树有一个根节点root。如果相邻的两座房子同时被进入,就会触发警报。一个小偷,最初只能访问root节点,并可以通过二叉树的边访问房子(注:访问不意味着进入),请问不触发警报的前提下他能偷到的财物的最大价值是多少?
以下面这棵二叉树为例,最多能偷走3+3+1=7的财物
[color=red]3[/color]
/ \
2 3
\ \
[color=red]3 1[/color]
分析:
这个问题乍一看上去可能没什么思路,但是如果是用递归,可以很优雅的解决这个问题,这需要读者对递归有比较深刻的理解。下面给出解决这个问题的java代码:
这个解法中比较重要的一点是使用了cache进行动态规划,使整个算法的时间复杂度为O(V+E),其中V为二叉树的节点的数量,E为二叉树的边的数量;如果不使用cache来缓存每一个节点的rob方法返回值,每次访问某个节点,都要重复计算一次rob值,最后的时间复杂度将会是指数级的,显然不可接受的。
以下面这棵二叉树为例,最多能偷走3+3+1=7的财物
[color=red]3[/color]
/ \
2 3
\ \
[color=red]3 1[/color]
分析:
这个问题乍一看上去可能没什么思路,但是如果是用递归,可以很优雅的解决这个问题,这需要读者对递归有比较深刻的理解。下面给出解决这个问题的java代码:
package houseRobberIII;
import java.util.HashMap;
import java.util.Map;
import common.TreeNode;
public class Solution {
//使用一个cache 缓存以每个节点为根节点的rob方法返回值,减少计算量
Map<TreeNode, Integer> cache = new HashMap<TreeNode, Integer>();
public int rob(TreeNode root) {
//如果当前节点为空 直接返回0
if(null == root){
return 0;
}
//首先查看缓存中有没有这个节点的rob方法返回值
if(null != cache.get(root)){
return cache.get(root);
}
//计算当前节点左孩子的rob方法返回值
int maxLeft = rob(root.left);
//计算当前节点右孩子的rob方法返回值
int maxRight = rob(root.right);
int maxLeftLeft = 0;
int maxLeftRight = 0;
//如果当前节点有左孩子
if(null != root.left){
//计算其左孩子的左孩子的rob值
maxLeftLeft = rob(root.left.left);
//计算其左孩子的右孩子的rob值
maxLeftRight = rob(root.left.right);
}
int maxRightLeft = 0;
int maxRightRight = 0;
//如果当前节点有右孩子
if(null != root.right){
//计算其右孩子的左孩子的rob值
maxRightLeft = rob(root.right.left);
//计算其右孩子的右孩子的rob值
maxRightRight = rob(root.right.right);
}
//不偷当前节点能偷到的财物的最大值
int notIncludeCurrentNodeMax = maxLeft + maxRight;
//偷当前节点能偷到的财物的最大值
int includeCurrentNodeMax = maxLeftLeft + maxLeftRight + maxRightLeft + maxRightRight + root.val;
//以其中的较大值作为当前节点的rob方法返回值
int res = notIncludeCurrentNodeMax > includeCurrentNodeMax ? notIncludeCurrentNodeMax : includeCurrentNodeMax;
//缓存当前节点的rob方法返回值
cache.put(root, res);
return res;
}
}
package common;
/**
* 二叉树节点类
* @author xuguanglv
*
*/
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) { val = x; }
}
这个解法中比较重要的一点是使用了cache进行动态规划,使整个算法的时间复杂度为O(V+E),其中V为二叉树的节点的数量,E为二叉树的边的数量;如果不使用cache来缓存每一个节点的rob方法返回值,每次访问某个节点,都要重复计算一次rob值,最后的时间复杂度将会是指数级的,显然不可接受的。