leetcode 链接:198. 打家劫舍

题目

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例:

  1. 输入:[1,2,3,1]
  2. 输出:4
  3. 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
  4. 偷窃到的最高金额 = 1 + 3 = 4
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

解答 & 代码

动态规划

  • dp 数组,dp[i] 代表第 0~i 间房屋能抢劫的总金额
  • 状态转移方程:dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
  • 初始化:dp[0] = nums[0], dp[1] = max(nums[0], nums[1])

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

    执行结果: ``` 执行结果:通过

执行用时:0 ms, 在所有 C++ 提交中击败了 100.00% 的用户 内存消耗:7.6 MB, 在所有 C++ 提交中击败了 38.86% 的用户


改进:<br />动态规划 + 滚动数组,无需使用 dp 数组存储<br />因为第 i 个状态只和前两个状态有关,因此只需使用两个状态变量即可
```cpp
class Solution {
public:
    int rob(vector<int>& nums) {
        int len = nums.size();
        if(len <= 0)
            return 0;
        if(len == 1)
            return nums[0];

        int dp0 = nums[0];
        int dp1 = max(nums[0], nums[1]);
        int dp = dp1;
        for(int i = 2; i < len; ++i)
        {
            dp = max(dp0 + nums[i], dp1);
            dp0 = dp1;
            dp1 = dp;
        }

        return dp;
    }
};
执行结果:通过

执行用时:4 ms, 在所有 C++ 提交中击败了 3887.20% 的用户