打家劫舍II
题目描述(LeetCode)
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [2,3,2] 输出: 3 解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入: [1,2,3,1] 输出: 4 解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。 偷窃到的最高金额 = 1 + 3 = 4 。
题目讲解
打家劫舍 II 和 打家劫舍 相比,题目只有一个变化。
这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。
这个规则会带来怎样的影响呢?
如果按照原来的解法,最要命的问题就是无法确定是否即抢了第一家又抢了最后一家。
那么,要怎么保证抢了第一家就不抢最后一家呢?
对于上面我们可以采取拆解的方式,变为两个打家劫舍I的方式,如下:
相比于第一题,此题目将首位也作为相邻,假设总共有N个房子,思路是:
1.分两次求解,首先是第一家到第N-1家,求得偷得最多的值,记Max01;
2.之后再次求得第2家到第N家可以偷的最大值,记为Max02;
3.最后比较Max01与Max02,将最大的那个值返回。
题目代码
对于上面的逻辑,用swift代码如下:
import UIKit let numsay: [Int] = [2,7,9,3,1] func robs(nums: [Int]) -> Int { if nums.count == 0 { return 0 } if nums.count == 1 { return nums[0] } if nums.count == 2 { if nums[0] < nums[1] { return nums[1] } else { return nums[0] } } var dp1 = [Int]() var dp2: [Int] = [0] /** *偷第一家与不偷第一家 */ var fk_1: Int = 0 var fk_2: Int = 0 //偷第一家 dp1.append(nums[0]) if dp1[0] < nums[1] { dp1.append(nums[1]) } else { dp1.append(dp1[0]) } for i in 0..<nums.count - 1 { if i >= 2 { fk_1 = dp1[i - 1] fk_2 = dp1[i - 2] + nums[i] let temp = fk_1 > fk_2 ? fk_1 : fk_2 dp1.append(temp) } } //不偷第一家,可以偷最后一家 dp2.append(nums[1]) if dp2[1] < nums[2] { dp2.append(nums[2]) } else { dp2.append(dp2[1]) } for i in 1..<nums.count { if i >= 3 { let fk_1 = dp2[i - 1] let fk_2 = dp2[i - 2] + nums[i] let temp = fk_1 > fk_2 ? fk_1 : fk_2 dp2.append(temp) } } //比较大小 let maxRobs = dp1[dp1.count - 1] > dp2[dp2.count - 1] ? dp1[dp1.count - 1] : dp2[dp2.count - 1] return maxRobs } let maxRobs = robs(nums: numsay) print(maxRobs)
通过playground打印出结果如下:
直接拷贝上面代码即可!
上面就是打家劫舍II的版本,希望对大家理解有所帮助,看完麻烦点个赞呗,谢谢!