Skip to content

Day 34


今天就是打家劫舍的一天,这个系列不算难,大家可以一口气拿下。

198.打家劫舍

题目链接:https://leetcode.cn/problems/house-robber

文章讲解:https://programmercarl.com/0198.打家劫舍.html

视频讲解:https://www.bilibili.com/video/BV1Te411N7SX

思路分析

题目要求相邻的房子不能偷,偷 i 还是不偷 i,这会影响下一步偷谁,进而确定递推公式

一维 dp

java
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++) {
            // 不偷 i:dp[i - 1];偷 i :dp[i - 2] + nums[i]
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp[nums.length - 1];
    }
}

213.打家劫舍 II

题目链接:https://leetcode.cn/problems/house-robber-ii

文章讲解:https://programmercarl.com/0213.打家劫舍II.html

视频讲解:https://www.bilibili.com/video/BV1oM411B7xq

思路分析

区别于打家劫舍 I,本题将线性数组转为环形,即选了起始位置,就不能选择终止位置(相邻位置不可以偷),思路就是将环形向线性转化

情况一:考虑不包含首尾元素

情况二:考虑包含首元素,不包含尾元素

情况三:考虑包含尾元素,不包含首元素

情况二和情况三包含了情况一,情况二、三分别看作是线性数组,取二者的最大值即为环形场景下的结果,这里的思路只是考虑元素,偷不偷由递推关系决定

一维 dp

java
class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return nums[0];
        }
        // 情况二
        int result1 = robAction(nums, 0, nums.length - 2);
        // 情况三
        int result2 = robAction(nums, 1, nums.length - 1);
        // 情况二和情况三取最大值
        return Math.max(result1, result2);
    }

    int robAction(int[] nums, int start, int end) {
        if (start == end) {
            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++) {
            // 不偷 i:dp[i - 1];偷 i :dp[i - 2] + nums[i]
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[end];
    }
}

337.打家劫舍 III

题目链接:https://leetcode.cn/problems/house-robber-iii

文章讲解:https://programmercarl.com/0337.打家劫舍III.html

视频讲解:https://www.bilibili.com/video/BV1H24y1Q7sY

思路分析

区别于打家劫舍 I,本题将线性数组转为二叉树,相邻的节点不可以偷,可以采用后序遍历,从叶子节点开始,逐层递推到根节点

对于根节点,分偷与不偷两种情况进行递归遍历,每个节点记录两个状态,偷与不偷的最大值

一维 dp

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

    int[] robAction(TreeNode root) {
        int[] res = new int[2];
        if (root == null) {
            return res;
        }

        // 后序遍历
        int[] left = robAction(root.left);
        int[] right = robAction(root.right);

        // 不偷根节点:res[0]
        res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
        // 偷根节点:res[1]
        res[1] = root.val + left[0] + right[0];
        return res;
    }

}