返回

偷房子II - 策略升级,环形思索

前端

在黑夜的掩护下,两个身手敏捷的窃贼再次出动,他们盯上了一排相连的房子。不过,这一次,他们遇到了一个新的挑战:这排房子的首尾相接,形成了一个环形。

由于相邻房子的警报系统会相互触发,聪明的窃贼们知道,他们无法连续抢劫相邻的两座房子。他们必须巧妙地规划自己的路线,以最大化他们的收益。

分治策略:

窃贼们意识到,他们可以将环形问题分解成两个较小的线性问题:

  1. 抢劫从第 1 间到第 n-1 间房子: 这相当于经典的 198. 打家劫舍问题,窃贼们无法抢劫最后第 n 间房子。
  2. 抢劫从第 2 间到第 n 间房子: 这也类似于 198. 打家劫舍问题,但这一次窃贼们无法抢劫第一间房子。

窃贼们可以通过计算这两个线性问题的最大收益,并选择收益最高的一个作为环形问题的解决方案。

动态规划实现:

为了有效地解决这个问题,窃贼们采用了动态规划的方法。他们创建了两个数组 dp1dp2,其中:

  • dp1[i] 表示从第 1 间到第 i 间房子抢劫所能获得的最大收益(不包括第 i 间房子)。
  • dp2[i] 表示从第 2 间到第 i 间房子抢劫所能获得的最大收益(不包括第 i 间房子)。

窃贼们使用以下递归公式计算动态规划数组的值:

dp1[i] = max(dp1[i-2] + nums[i], dp1[i-1])
dp2[i] = max(dp2[i-2] + nums[i], dp2[i-1])

其中,nums 数组存储了每间房子的价值。

选择最佳方案:

计算完动态规划数组后,窃贼们需要选择最佳方案。他们计算环形问题的最大收益为:

max(dp1[n-1], dp2[n])

因为这表示从第 1 间到第 n-1 间房子或从第 2 间到第 n 间房子抢劫所获得的最大收益。

代码示例:

def rob_house_ring(nums):
    n = len(nums)
    if n == 0:
        return 0

    # 初始化动态规划数组
    dp1 = [0] * n
    dp2 = [0] * n

    # 计算从第 1 间到第 n-1 间房子的最大收益
    for i in range(1, n):
        dp1[i] = max(dp1[i-2] + nums[i], dp1[i-1])

    # 计算从第 2 间到第 n 间房子的最大收益
    for i in range(1, n):
        dp2[i] = max(dp2[i-2] + nums[i], dp2[i-1])

    # 选择最佳方案
    return max(dp1[n-1], dp2[n])

总结:

通过巧妙地将环形问题分解成两个线性问题,并采用动态规划的方法,窃贼们成功地解决了 213. 打家劫舍-II 问题。这种分治思想和动态规划技巧在解决许多复杂的计算机科学问题中都发挥着至关重要的作用。