代码随想录算法训练营第四十八天| LeetCode198.打家劫舍、LeetCode213.打家劫舍II、LeetCode337.打家劫舍III

LeetCode198.打家劫舍

题目链接:198.打家劫舍

思路:

第一步:确定 dp 数组所表示的含义,dp[i] 表示包括下标为 i 的房屋,最高可以偷窃的金额为 dp[i]。

第二步:确定递推公式,决定 dp[i] 的值的问题在于第 i 个房间偷还是不偷;

如果偷窃第 i 个房间,则 dp[i] = dp[i - 2] + nums[i];

如果不偷窃第 i 个房间,则 dp[i] = dp[i - 1];

对于上面两种情况取其最大值,所以 dp 数组的递推公式为
d p [ i ] = M a t h . m a x ( d p [ i − 1 ] , d p [ i − 2 ] + n u m s [ i ] ) dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]) dp[i]=Math.max(dp[i1],dp[i2]+nums[i])
第三步:初始化,从递推公式可以得出,需要初始化 dp[0] 和 dp[1];

所以,dp[0] = nums[0];对于 dp[1] , dp[1] = Math.max(nums[0], nums[1]);

第四步:遍历,从i = 2 开始进行遍历,遍历整个 nums 数组。

代码:

class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0){
            return 0;
        }
        if (nums.length == 1){
            return nums[0];
        }
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < nums.length; i++){
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[nums.length - 1];
    }
}

LeetCode 213.打家劫舍II

题目链接:213.打家劫舍II

思路:

本题思路与LeetCode198.打家劫舍思路相同。

不同之处:第一个房屋和最后一个房屋是相连的,即所有的房屋组成了一个环。所以,将情况进行细分为两种情况。

  • 情况一:不包含最后一个房屋,房屋数组的的大小为 (0, nums.length - 2);
  • 情况二:不包含第一个房屋,房屋数组的大小为 (1, num.length - 1);

分别对上面两种情况进行分析,从中取出最大值。

代码:

class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0){
            return 0;
        }
        if (nums.length == 1){
            return nums[0];
        }
        int result1 = robRange(nums, 0, nums.length - 2);
        int result2 = robRange(nums, 1, nums.length - 1);
        return Math.max(result1, result2);
    }

    private int robRange(int[] nums, int start, int end) {
        if (end == start){
            return nums[start];
        }
        int[] dp = new int[nums.length];
        dp[start] = nums[start];
        dp[start + 1] = Math.max(nums[start], nums[start + 1]);
        for (int i = start + 2; i <= end; i++){
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[end];
    }
}

LeetCode 337.打家劫舍III

题目链接:337.打家劫舍III

思路:

本题涉及二叉树的知识,对二叉树的递归三部曲进行分析。

第一步:确定递归函数的参数和返回值(以及 dp 数组的所表示的含义)

定义一个递归函数为 int[] dp = robTree(TreeNode root)

dp 数组的下标所表示的含义,dp[0] 表示不偷窃该节点所获得的最高金钱,dp[1] 表示偷窃该节点所获得的最高金钱。

第二步:确定终止条件,当遇到空节点时,进行终止并返回。

第三步,确定遍历顺序,本题采用的是后序遍历。因为通过递归函数的返回值去做下一步的计算。

首先通过在左节点进行递归操作,获取偷或不偷左节点的金钱;

通过在右节点进行递归操作,获取偷或不偷右节点的金钱。

第四步:确定单层递归逻辑,分为两种情况,

  • 情况一:不偷窃当前节点,res[0] = root.val + left[0] + right[0]
  • 情况二:偷窃当前节点,res[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1])

代码:

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

    private int[] robTree(TreeNode root) {
        int[] res = new int[2];
        if (root == null){
            return res;
        }
        int[] left = robTree(root.left);
        int[] right = robTree(root.right);

        res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        res[1] = root.val + left[0] + right[0];
        return res;
    }
}

你可能感兴趣的:(算法,leetcode,算法,动态规划)