213. 打家劫舍 II:动态规划

356 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

题目描述

这是 力扣上的 213. 打家劫舍 II,难度为 中等

题目分析

关于打家劫舍 II,自然是打家劫舍的进阶版,但是我们思考一下是否可以使用上一次的方式呢,还得咱们来好好分析一波

首先总体来说,小偷偷窃房屋,是不能偷相邻的房间的,否则就会触发告警,那么对于如何找到小偷能够偷到的最大现金那么我们思考方式和上一次类似,对于有 1 个房间,2 个房间,和多个房间的时候,我们的处理方式有何不同

咱们挨着房间偷,不能偷相邻的,那么偷到当前房间时想获得最大的现金,那么是依赖于偷的上一个房间时也是当时的最大现金

这个时候就有

只有 1 个房间的时候,那么 dp[0] = nums[0] ,dp 数组表示到索引为 i 的位置时,对应偷到的最多的现金

若是 2 个房间的时候,无论是否环形,我们也是只能偷其中 1 间,即 dp[1] = max(nums[0], nums[1])

若是 2 个以上的房间时,咱们需要如何去思考呢?

若还是保持之前的思考,那么就会出现偷了整个环形房间的头,同时也偷了环形房间的尾,这个是不允许的,过度危险,只要进橘子的

既然题目很明确告诉我们不能同时偷环形房间的头和尾,那么,咱们是不是可以分成 2 中情况:

  • 就是不偷环形房间的头

不偷头,那么说明,咱们偷窃的范围是 nums[1:n-1],这个时候,问题就变成了对于数组 nums[1:n-1],我们能偷到的最大现金是多少?

  • 就是不偷环形房间的尾

不偷尾,那么说明,咱们的偷窃范围是 nums[:n-2],这个时候,同理,问题也就变成了对于数组 nums[:n-2] ,我们能偷到的最大现金是多少?

那么这个时候,相当于就已经分成了 2 种情况,咱们去取最大值即可

那么总的来说,咱们还是去使用 动态规划的方式来进行处理,就能够得到如下递推公式了:

可以看到和上一次的地推公式完全一样,但是,我们需要注意的是 当 房间数大于 2 的时候,咱们需要注意控制偷的范围

接下来,咱们就可以来实现编码了,咱们这次使用 golang 的方式来进行实现

Golang 的实现方式:

func help(nums []int) int {
    first, second := nums[0], max(nums[0], nums[1])
    for _, v := range nums[2:] {
        first, second = second, max(first+v, second)
    }
    return second
}

func rob(nums []int) int {
    n := len(nums)
    if n == 1 {
        return nums[0]
    }
    if n == 2 {
        return max(nums[0], nums[1])
    }
    return max(help(nums[:n-1]), help(nums[1:]))
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

这种实现方式,咱们的时间复杂度为 O(n),此处的 n 即为 nums 数组的长度, 空间复杂度为 O(1)

今天就到这里,若有偏差,还请斧正

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~