leetcode196 & leetcode337 打家劫舍

leetcode196 打家劫舍

题目描述

leetcode196 & leetcode337 打家劫舍_第1张图片

题目详解:动态规划

由题目可知:

  1. 当nums.length == 0时,输出为0;当nums.length == 1时,输出为nums[0];
  2. 当nums.length == 2时,输出为max(nums[0], nums[1])
  3. 当nums.leng == 3时,有两种选择,一是不选择nums[2] 则最大偷窃金额为res[1],二是选择nums[2] 则最大偷窃金额为res[0] + nums[2]
  4. 以此类推:res[n] = max(res[n - 1], res[n - 2] + nums[n])
public int rob(int[] nums){
        if(nums.length == 0)
            return 0;
        if(nums.length == 1)
            return nums[0];
        int[] res = new int[nums.length];
        res[0] = nums[0];
        res[1] = Math.max(res[0], nums[1]);
        for(int i = 2; i < nums.length; i ++){
            res[i] = Math.max(res[i - 2] + nums[i], res[i - 1]);
        }
        return res[nums.length - 1];
    }

leetcode337 打家劫舍 Ⅲ

题目描述

leetcode196 & leetcode337 打家劫舍_第2张图片leetcode196 & leetcode337 打家劫舍_第3张图片

题目解析

本题是leetcode196的升级版,即一维序列换成了二叉树,有连接的两个节点不能同时被偷,这是一道动态规划在二叉树中的应用。

递归方法 + 暴力枚举

对于一棵三层的完全二叉树,有一个爷爷节点,两个孩子节点和四个孙子节点,如果爷爷节点被偷,则其孩子节点不能被偷,最大盗取金额为两个孙子节点最大盗取金额之和;如果爷爷节点不被偷,则最大盗取金额为两个孩子节点最大盗取金额之和。因此,可以用递归方法来实现,递归表达式为 :

  1. 爷爷节点被偷时,money = root.val + rob(root.left.left) + rob(root.left.right) + rob(root.right.left) + rob(root.right.right)
  2. 爷爷节点不被偷时, money = rob(root.left) + rob(root.right)
  3. 最终的最大盗取金额为1,2中的最大值
public int rob(TreeNode root){
        if(root == null) return 0;
        int money = root.val;
        if(root.left != null){
                money += rob(root.left.left) + rob(root.left.right);
        }
        if(root.right != null){
                money += rob(root.right.left) + rob(root.right.right);
        }
        return Math.max(money, rob(root.left) + rob(root.right));

    }

递归优化

对于一棵二叉树,如果根节点被偷,则其左右孩子节点不能被偷;若根节点不被偷,则最大盗取的金额为左右子树偷取的最大金额之和。最终的最大盗取金额为上述两者的最大值。因此我们能够运用递归算法进行遍历求解。

  1. 我们对每一个节点设置两个装填,res[0] 中存取root节点被偷的最大盗取金额,res[1]中存取root节点不被偷的最大盗取金额;
  2. 对于res[0]的情况,如果root节点被偷,则其左右孩子节点都不能被偷,因此res[0] = left[1] + right[1]
  3. 对于res[1]的情况,如果root节点不被偷,则最大盗取金额为左右子树的最大盗取金额之和, 即 res[1] = max(left[0], left[1]) + max(right[0], right[1])
  4. 最终的最大盗取金额为 max(res[0], res[1])
public int rob(TreeNode root){
        int[] res = interRob(root);
        return  Math.max(res[0], res[1]);   // 返回偷或不偷root节点中的最大值
    }
    private int[] interRob(TreeNode root){
        if(root == null)    return new int[2];
        int[] res = new int[2]; // 0代表偷;1代表不偷

        int[] left = interRob(root.left);
        int[] right = interRob(root.right);

        res[0] = root.val + left[1] + right[1]; //root节点被偷,则左右孩子节点不能被偷
        res[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);    //root节点不偷, 则偷左右节点的最大值和
        return res;
    }

你可能感兴趣的:(leetcode,Java)