[LeetCode] House Robber 题解

前言

House Robber算是LeetCode动态规划tag下的入门题,相当简单。

题目

题目链接:https://leetcode.com/problems/house-robber/
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

这个题还是挺好玩的,小偷准备偷完整条街,但是因为报警系统的限制,不能连着偷两个相邻的房屋,给出一个数组表示整条街上所有房屋中的钱数,求出小偷在不触发报警系统的情况下所能偷盗的最大数额。

分析

这道题的关键就在于小偷不能偷盗“two adjacent houses”。现在先想想最简单的情况:只有一栋房子,那么小偷能偷到的钱就是这间屋子的钱。只有两栋房子的话,选钱多的那个偷就行。
想明白了最简单的情况,现在略过中间那么多可能性的组合,直接假设现在已经偷到这条街的最后几栋房屋了——
[LeetCode] House Robber 题解_第1张图片
那么对于此时的情况,我们用nums[i]表示第i个房屋中的钱数,dp[i]表示偷完第i个房屋后一共能获得的最多钱数,注意:偷完第i个房屋不一定代表第i个房屋被偷了,也有可能是它前面相邻的屋子被偷了。 显然,对于最后三栋屋子,要么偷i-2和i,要么只偷i-1,在这两种决策中选出最优解(即偷得金额最大者)即为偷完整条街(即偷完第i个房屋后)所获得的最大金额dp[i]。
于是得到这样的式子:

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

对于偷盗过程中间的房屋,此式依然成立,于是得到这样的代码:

    dp[0] = nums[0];
    dp[1] = std::max(nums[0],nums[1]);
    for (int i = 2; i < n; i++) {
      dp[i] = std::max(nums[i]+dp[i-2], dp[i-1]);
    }

代码

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

另外,把上述思路从次序奇偶的角度重新思考整理一下,可以得到相对而言更简洁的写法:

class Solution {
public:
  int rob(vector<int>& nums) {
    int n = nums.size(), odd = 0, even = 0;
    for (int i = 0; i < n; i++) {
      if (i % 2 == 0) {
        even = max(odd, even+nums[i]);
      } else {
        odd = max(even, odd+nums[i]);
      }
    }
  return max(odd, even);
  }
};

你可能感兴趣的:(算法与数据结构,LeetCode)