LeetCode 213. 打家劫舍 II:题解|刷题打卡

·  阅读 103

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、题目描述:

原题链接

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

示例 1:

输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
复制代码

二、思路分析:

因为不能选择相邻的房屋,一种简单的推测是只偷奇数或者只偷偶数号房屋,但是很可惜这种推测是错误的,因为除了间隔一间房屋来偷,还可以间隔两间房屋来偷,并不是每走两步就必须偷一间,而使用动态规划思想就可以得到最优解了。

假设我们是从前往后依次来偷的,那么当我们位于第 ii 间房屋的时候,偷不偷 ii 号房只和前面位于前面两间房屋的最大收益有关,一种可能是偷了 i2i - 2 号房 并且偷了 ii 号房,还有一种可能是偷了 i1i - 1 号房,就不能偷 ii 号房了。

让我们用 dp[i]dp[i] 表示在 ii 号房的最大收益,那么很容易地写出状态方程:dp[i]=max(dp[i1],dp[i2]+nums[i])dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]),然后注意一下边界情况就行。因为这道题还有一个限制条件:第一个和最后一个房屋是相邻的,偷了第一间就不能偷最后一间,所以我们需要分情况求解选最大值。

三、AC 代码:

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        if (n == 1) {
            return nums[0];
        }
        if (n == 2) {
            return max(nums[0], nums[1]);
        }
        vector<int> dp(n);
        dp[0] = nums[0], dp[1] = max(nums[0], nums[1]);
        for (int i = 2; i < n - 1; ++i) {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        int ans = dp[n - 2];
        dp[1] = nums[1], dp[2] = max(nums[1], nums[2]);
        for (int i = 3; i < n; ++i) {
            dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return max(ans, dp[n - 1]);
    }
};
复制代码

四、总结:

在解决一些分步的最优化题目时,动态规划往往是个不错的选择,因为动态规划能有效降低时间复杂度,而且有时所产生的的额外空间复杂度也能得到优化,比如这道题就可以使用滚动数组来替代整个 dpdp 数组将空间复杂度降至 O(1)O(1),感兴趣的同学可以尝试一下。

分类:
代码人生
标签:
分类:
代码人生
标签:
收藏成功!
已添加到「」, 点击更改