以下面这棵二叉树为例,最多能偷走3+3+1=7的财物
3
/ \
2 3
\ \
3 1
分析:
这个问题乍一看上去可能没什么思路,但是如果是用递归,可以很优雅的解决这个问题,这需要读者对递归有比较深刻的理解。下面给出解决这个问题的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值,最后的时间复杂度将会是指数级的,显然不可接受的。