【详细整理】动态规划之——337. 打家劫舍 III

352 阅读2分钟

题目

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。 计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

来自 leetcode-cn.com/problems/ho…

思路+代码

求最值,穷举,bp问题。先明确状态转移方程,bp函数肯定就是求当前这个节点能偷到的最大的钱

对于每一个节点有两种情况:1、偷这个节点,然后偷它的孙子节点 2、不偷这个节点,然后偷它的子节点。

base case就是null

然后返回值就是这个节点能偷到的最多的钱,就是以上两个求max,然后记得用备忘录优化。

class Solution {
    // 动态规划问题
    public int rob(TreeNode root) {
    //    使用备忘录储存用过的值,进行优化
        HashMap<TreeNode,Integer> memo = new HashMap<>();
        return tou(root,memo);
    }
    public int tou(TreeNode root,HashMap<TreeNode,Integer> memo){
        // base case
        if (root == null){
            return 0;
        }
        if(memo.containsKey(root)){
            return memo.get(root);
        }
        // 状态转移方程
        int res = root.val;
        if(root.left != null){
            res += tou(root.left.left,memo)+tou(root.left.right,memo);
        }
        if(root.right != null){
            res += tou(root.right.left,memo)+tou(root.right.right,memo);
        }
        int result = Math.max(res,tou(root.right,memo)+tou(root.left,memo));
        // 放入备忘录
        memo.put(root,result);
        return result;
    }
}

优化压缩

因为其实每个节点都只有偷和不偷两个状态,所以只需要储存至两个状态就可以。0表示不偷,1表示偷。则:

任何一个节点能偷到的最大钱的状态可以定义为

当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱 当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数

直接写出下面这个代码,有个问题:

class Solution {
    public int rob(TreeNode root) {
        int [] result = bp(root);
        return Math.max(result[0],result[1]);

    }
    public int[] bp(TreeNode root){
        if(root == null){
            return new int[2];
        }
        int[] res =new int[2];
        int[] left = bp(root.left);
        int[] right = bp(root.right);
        res[0] = left[1]+right[1];
        res[1] = root.val + left[0] +right[0];
        return res;

    }
}

这个代码有个问题:

image.png 就是这个节点不偷的时候,它的左右节点也可以不偷(跨两层偷,只要值最大)

class Solution {
    public int rob(TreeNode root) {
        int [] result = bp(root);
        return Math.max(result[0],result[1]);

    }
    public int[] bp(TreeNode root){
        if(root == null){
            return new int[2];
        }
        int[] res =new int[2];
        int[] left = bp(root.left);
        int[] right = bp(root.right);
        // res[0] = left[1]+right[1];
        res[0] = Math.max(left[1],left[0])+Math.max(right[1],right[0]);
        res[1] = root.val + left[0] +right[0];
        return res;

    }
}