社区内互不相邻的房间内财物之和的最大值

一个很有意思的问题,一个社区,所有的房子构成一棵二叉树,每个房子里有一定价值的财物,这棵二叉树有一个根节点root。如果相邻的两座房子同时被进入,就会触发警报。一个小偷,最初只能访问root节点,并可以通过二叉树的边访问房子(注:访问不意味着进入),请问不触发警报的前提下他能偷到的财物的最大价值是多少?

以下面这棵二叉树为例,最多能偷走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值,最后的时间复杂度将会是指数级的,显然不可接受的。

猜你喜欢

转载自xglv2013.iteye.com/blog/2309638