Nameless Site

But one day, you will stand before its decrepit gate,without really knowing why.

0%

打家劫舍II

来自Leetcode第213题打家劫舍II

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

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

示例 1:

1
2
3
输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

动态规划

环状排列意味着第一个房子和最后一个房子中只能选择一个偷窃,因此可以把此环状排列房间问题约化为两个单排排列房间子问题:

  1. 在不偷窃第一个房子的情况下(即 nums[1:]),最大金额是 p1 ;
  2. 在不偷窃最后一个房子的情况下(即 nums[:n−1]),最大金额是 p2 。
  • 综合偷窃最大金额: 为以上两种情况的较大值,即 max(p1,p2) 。

记:

f(k) = 从前 k 个房屋中能抢劫到的最大数额,Ai = 第 i 个房屋的钱数。

首先看 n = 1 的情况,显然 f(1) = A1。

再看 n = 2f(2) = max(A1, A2)。

对于 n = 3,有两个选项:

  1. 抢第三个房子,将数额与第一个房子相加。
  2. 不抢第三个房子,保持现有最大数额。

显然,你想选择数额更大的选项。于是,可以总结出公式:

f(k) = max(f(k – 2) + A_k, f(k – 1))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public int rob(int[] nums) {
if(nums.length == 0)
return 0;
if(nums.length == 1)
return nums[0];
return Math.max(helper(Arrays.copyOfRange(nums,0,nums.length - 1)),helper(Arrays.copyOfRange(nums,1,nums.length)));
}

private int helper(int []nums){
int pre = 0, cur = 0;
int tmp;
for(int x : nums){
tmp = cur;
cur = Math.max(pre + x,cur);
pre = tmp;
}
return cur;
}