[每日算法] leetcode第198题 House Robber 和 第213题 House Robber II

198. 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.

Example 1:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.

Example 2:

Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.

题目大意

将该题转化一下表达方法,即是求一个数组中某一种序列的元素和的最大值,要求该种序列中的任意两个元素在数组中的位置都不相邻。

解题思路

该题归类为DP,所以很明显是往DP的方向去思考,如何将问题转化为子问题,并求出其递归方程。
对于一个数组,数组长度为len
我们可以分为两种情况:

  • 一种是最后一个元素要取,此时取了最后一个元素,倒数第二个元素与它相邻,则必不取,则此时序列最大值为前len-2个元素的序列最大值加上最后一个元素的值。
  • 一种是最后一个元素不取,则倒数第二个元素可取,此时序列最大值为前len-1个元素的序列最大值。

然后综合两种情况的最大值,我们就可以得到当前数组的序列最大值。
很明显,无论是求前len-2个元素的序列最大值,还是求前len-1个元素的序列最大值,都可以转化为该问题的子问题,再往下分为两种情况继续往下。
那么,分到什么元素停止呢?

  • 当len为1时,我们要求的最大值就是该数组中唯一一个元素的最大值。
  • 当len为2时,我们要求的最大值就是该数组两个元素其中的较大值。
    上面两种情况即为往下分到最后的情况。
    当然,运算过程会有很多种情况,所以我们可以用一个数组存储中间值,然后每次往下递归前先看一下该值是否已经计算过,可以大大减少冗余递归的时间。

C++实现代码

int a[10000] = {};

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

    int getMaxCount(vector<int>& nums, int len) {
        if (a[len] >= 0) {
            return a[len];
        }
        if (len >= 3) {
            a[len] = max(getMaxCount(nums, len-1), getMaxCount(nums, len-2)+nums[len-1]);
            return a[len];
        } else if (len == 1) {
            a[len] = nums[0];
            return a[len];
        } else if (len == 2) {
            a[len] = max(nums[0], nums[1]);
            return a[len];
        }
    }
};

213. House Robber II

原题目描述

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, 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.

Example 1:

Input: [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2),
             because they are adjacent houses.

Example 2:

Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
             Total amount you can rob = 1 + 3 = 4.

题目大意

该题是上一道题的进阶版,唯一修改的条件是数组的首部和尾部相连形成循环数组,即首部和尾部现在是相邻的了。

解题思路

上一道我们使用的是DP解决,那么这一道我们能不能继续使用这一种思路呢,当然是能了,因为首部和尾部现在相邻,所以我们可以肯定的一点:

  • 如果我们选择了首部,就一定不会选择尾部;
  • 如果我们选择了尾部,就一定不会选择首部;

根据这一规律,我们可以将分成两种情况来求这个循环数组的序列最大值:

  • 第一种情况,去除尾部,则此时很明显,该数组变为了一个非循环数组,求序列最大值可以使用上面那道题的解决办法。
  • 第二种情况,去除首部,跟第一种情况类似解决。

所以此时该循环数组的序列最大值就是上面两种情况求出的值的较大值,该问题便转化为两个子问题,而这两个子问题在第一题我们便解决了。

C++代码实现

int a[10000] = {};

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

    int getMaxCount(vector<int>& nums, int len) {
        if (a[len] >= 0) {
            return a[len];
        }
        if (len >= 3) {
            a[len] = max(getMaxCount(nums, len-1), getMaxCount(nums, len-2)+nums[len-1]);
            return a[len];
        } else if (len == 1) {
            a[len] = nums[0];
            return a[len];
        } else if (len == 2) {
            a[len] = max(nums[0], nums[1]);
            return a[len];
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值