在问 · 算法题解

213. 打家劫舍 II

题目描述

若干间房子排成一个环,nums[i] 是第 i 间房子里的现金,都是非负整数。由于是环形,第一间与最后一间也相邻。

相邻房子的防盗系统相连:同一晚闯入任意两间相邻房子都会报警。

在不报警的前提下,返回今晚最多能偷到多少钱。

示例 1
输入:nums = [2,3,2]
输出:3

解释:第 1 间和第 3 间首尾相邻,不能同时偷,只偷中间的 3 最好。

示例 2
输入:nums = [1,2,3,1]
输出:4

解释:偷第 1 间和第 3 间,共 1 + 3 = 4。

示例 3
输入:nums = [1,2,3]
输出:3

解释:三间两两相邻,只能偷一间,最多拿 3。

数据范围

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 1000

解题思路

环的麻烦只在于首尾不能同时选。分两种情况:不偷最后一间(只看 nums[0..n-2]),或不偷第一间(只看 nums[1..n-1])。两种情况都变成一排房子的打家劫舍,用滚动变量 a、b 分别表示“到前前一间”和“到前一间”的最优值,答案取两者较大值。只有一间房时直接返回它。

为什么正确

处理完第 i 间后,b 是这一排中到第 i 间为止的最大金额,a 是到第 i-1 间为止的最大金额。

复杂度分析

时间 O(n),空间 O(1)。

易错点

只有一间房时,两排都是空的,会得到 0,必须特判返回 nums[0]。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def rob(self, nums: List[int]) -> int:
        def line(lo, hi):
            a, b = 0, 0
            for i in range(lo, hi):
                a, b = b, max(b, a + nums[i])
            return b
        if len(nums) == 1:
            return nums[0]
        return max(line(0, len(nums) - 1), line(1, len(nums)))

载入编辑器,自己跑一遍 →

动态规划 专题的其他题目

查看 动态规划 全部题目 →