首页 > 试题广场 >

打家劫舍(三)

[编程题]打家劫舍(三)
  • 热度指数:1835 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
你是一个经验丰富的小偷,经过上次在街边和湖边得手后你准备挑战一次自己,你发现了一个结构如二叉树的小区,小区内每个房间都存有一定现金,你观察到除了小区入口的房间以外每个房间都有且仅有一个父房间和至多两个子房间。
问,给定一个二叉树结构的小区,如之前两次行动一样,你无法在不触动警报的情况下同时偷窃两个相邻的房间,在不触动警报的情况下最多的偷窃金额。

1.如果输入的二叉树为{2,1,2,#,2,#,1},那么形状结构如下:


小区入口的房间的值是2 ,偷窃第一层2和第三层 2,1 是最优方案。




2.如果输入的二叉树为{3,2,10},那么形状结构如下:

样例2:小区入口的房间的值是3 ,偷窃第二层 2,10 是最优方案。

数据范围:二叉树节点数量满足 ,树上的值满足
示例1

输入

{2,1,2,#,2,#,1}

输出

5
示例2

输入

{3,2,10}

输出

12
示例3

输入

{3,5,#,10}

输出

13

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    //mp1,mp2分别表示当前节点偷或不偷的最大金额
    HashMap<TreeNode,Integer> mp1=new HashMap();
    HashMap<TreeNode,Integer> mp2=new HashMap();
     
    public int rob (TreeNode root) {
        mp1.put(null,0);
        mp2.put(null,0);
        f(root);//递归
        return Math.max(mp1.get(root),mp2.get(root));//返回最大值
    }
    void f(TreeNode root){//递归
        if(root==null)
            return;
        f(root.left);//左递归
        f(root.right);//右递归
        mp1.put(root,root.val+mp2.get(root.left)+mp2.get(root.right));//当前节点偷
        mp2.put(root,Math.max(mp1.get(root.left),mp2.get(root.left))+Math.max(mp1.get(root.right),mp2.get(root.right)));//当前节点不偷
    }
}
发表于 2022-03-09 15:34:58 回复(0)
这一系列打家劫舍问题出得真好,循序渐进:线性DP->考虑环形的DP->树型DP。本题是一个非常明显的树型DP问题,对于每一个节点,在决定是否偷窃这个节点房间的财物时,我们还需要向左右孩子的房间索要两个信息:
  1. 偷窃孩子节点房间的财物时,得到的最大收益steal
  2. 不偷窃孩子节点房间的财物时,得到的最大收益noSteal
构建包含这两个信息的结构体Info,然后深度优先搜索,自底向上累加收益,当根节点得到信息体时,返回偷与不偷根节点房间的两个方案中,更大的那个收益就可以了。
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

class Info {
    public int steal;
    public int noSteal;
    public Info(int steal, int noSteal) {
        this.steal = steal;
        this.noSteal = noSteal;
    }
}

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return int整型
     */
    public int rob (TreeNode root) {
        // write code here
        Info info = process(root);
        return Math.max(info.steal, info.noSteal);
    }
    
    private Info process(TreeNode root) {
        if(root == null){
            return new Info(0, 0);
        }
        Info leftInfo = process(root.left);
        Info rightInfo = process(root.right);
        // 这一间偷,下面相邻的就不能偷
        int steal = root.val + leftInfo.noSteal + rightInfo.noSteal;
        // 这一间不偷,那下面相邻的可以偷可以不偷,选择收益大的方案
        int noSteal = Math.max(
            Math.max(leftInfo.steal + rightInfo.steal, 
                     leftInfo.noSteal + rightInfo.noSteal), 
            Math.max(leftInfo.steal + rightInfo.noSteal, 
                     leftInfo.noSteal + rightInfo.steal)
        );
        return new Info(steal, noSteal);
    }
}

发表于 2021-12-15 22:03:03 回复(0)