[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”。现在先想想最简单的情况:只有一栋房子,那么小偷能偷到的钱就是这间屋子的钱。只有两栋房子的话,选钱多的那个偷就行。
想明白了最简单的情况,现在略过中间那么多可能性的组合,直接假设现在已经偷到这条街的最后几栋房屋了——
QQ截图20160303145603.jpg
那么对于此时的情况,我们用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);
  }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值