题目

大家好!今天给大家带来的是一道很有意思的题目:打家劫舍。
原贴地址:http://leanote.com/blog/post/6077ab41ab644104e70017ff

题目

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析

这个题目,如果去掉上面那个围成一圈,一看就是一个非常经典的动态规划题目,
当我们每次遍历到一个房子的时候,有两个选择,一个是抢(从而放弃了抢该房子之前一座房子的权利),一个是不抢,假设我们对每个房子维护一个从左往右抢,抢到该房子时能获得的最大价值,那么状态转移方程就是

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

当然这都是假设在房子没有围城一圈的情况下的。
那么如果这些房子围城一圈了呢?大家考虑一下围城一圈和之前最大的变化是什么,其实就是原本可以同时选择首位两座房子,现在不行,两座房子中必定有一座不能被选择。
鉴于此,我们可以分出两种情况讨论,一种不选择头房子,一种不选择尾房子,这样两种情况再套用没有圈的方法来计算,最后再取一个最大值就解决了。
C++代码

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        if (n == 0) return 0;
        if (n == 1) return nums[0];
        vector<int> nohead = nums, notail = nums;
        nohead.erase(nohead.begin());
        notail.pop_back();
        return max(nocirclerob(nohead), nocirclerob(notail));
    }
    int nocirclerob(vector<int>& nums) {
        int n = nums.size();
        if (n == 0) return 0;
        vector<int> ret = {0, nums[0]};
        for (int i = 1; i < n; ++i) {
            ret.push_back(max(ret[ret.size() - 2] + nums[i], ret.back()));
        }
        return ret.back();
    }
};

为了方便大家观察,我已经将函数和变量的名称重新更改过了。nohead和notail两个数组大家通过名字就能看出,一个是没有头房子,一个是没有尾房子。还有下面的nocirclerob函数,就是在没有围城圆圈的时候使用的动态规划函数。当然别忘了,有一些特殊情况需要我们特殊处理,比如一开始只有0座房子和1座房子,就得靠我们在入口的地方特殊处理一下。
Rust代码

pub fn nocirclerob(nums: Vec<i32>) -> i32 {
    let n = nums.len();
    let mut res = vec![0, nums[0]];
    for i in 1..n {
        res.push(res[res.len() - 1].max(res[res.len() - 2] + nums[i]));
    }
    res.pop().unwrap()
}
impl Solution {
    pub fn rob(nums: Vec<i32>) -> i32 {
        let n = nums.len();
        if n == 0 {
            return 0;
        } else if n == 1 {
            return nums[0];
        }
        let mut nohead = nums.clone();
        let mut notail = nums.clone();
        nohead.remove(0);
        notail.pop();
        nocirclerob(nohead).max(nocirclerob(notail))
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值