【DP】LeetCode 198. 打家劫舍

题目链接

198. 打家劫舍

思路

分析动态规划题目的时候只需要考虑最后一个阶段,因为所有的阶段转化都是相同的,考虑最后一个阶段容易发现规律

在数组的动态规划问题中,一般 dp[i] 都是表示以 nums 以前 i 个元素组成(即 nums[i - 1])的状态;dp[i][j] 分别表示以 nums1 前 i 个元素(即 nums1[i - 1])组成和以 nums2 前 j 个元素(即 nums2[j - 1])组成的状态,以此类推

字符串也是个数组,是字符数组

表示状态

状态表示就是靠猜,但是会有猜的套路,一般都是通过最终结果和数组数量来猜

这是一道非常经典的动态规划题目

我们定义 \(dp[i]\) 为打劫前 i 个房屋所能获得的最大金额

找状态转移方程

思考的方向是:大问题的最优解怎么由小问题的最优解得到

当我们打劫到第 i 个房屋的时候,有两个策略:

  1. 打劫第 i - 1 个房屋,跳过第 i 个房屋
  2. 打劫第 i 个房屋,跳过第 i - 1个房屋

二者取最大值,能得到状态转移方程:

\[dp[i] = \max(dp[i - 1], dp[i - 2] + nums[i - 1]); \]

边界处理

\[dp[1] = nums[0] \]

空间优化

使用三个变量 \(pre1\)\(pre2\)\(current\) 分别表示 \(dp[i - 2]\)\(dp[i - 1]\)\(dp[i]\),循环滚动更新

代码

dp数组版

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        // dp[i] 表示前 i 个房屋能打劫到的金额
        int[] dp = new int[n + 1];

        dp[1] = nums[0];
        for(int i = 2; i <= n; i++){
            // 不选 nums[i - 1]和选 nums[i - 1] 之间取最大值
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i - 1]);
        }

        return dp[n];
    }
}

空间优化版

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        // dp[i] 表示前 i 个房屋能打劫到的金额
        // pre1 表示 dp[i - 2]
        int pre1 = 0;
        // pre2 表示 dp[i - 1]
        int pre2 = nums[0];
        int current = 0;

        for(int i = 2; i <= n; i++){
            // 不选 nums[i - 1]和选 nums[i - 1] 之间取最大值
            current = Math.max(pre2, pre1 + nums[i - 1]);
            pre1 = pre2;
            pre2 = current;
        }

        return pre2;
    }
}
posted @ 2023-04-25 10:48  Frodo1124  阅读(23)  评论(0编辑  收藏  举报