「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」
题目
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。
示例 1:
输入:nums = [2,3,2] 输出:3 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2: 输入:nums = [1,2,3,1] 输出:4 解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 。
示例 3: 输入:nums = [0] 输出:0
提示:
- 1 <= nums.length <= 100
- 0 <= nums[i] <= 1000
解题思路
本题重点在于房屋是环状排列,意味着第一个房子和最后一个房子中只能选择一个偷窃(或者都不偷窃)。这样可以分为三种情况:
- 首尾两个房子都不抢
- 抢第一间房子,不抢最后一间
- 抢最后一间房子,不抢第一间
我们可以发现无论如何情况2,3偷盗区间都比1要大,也就是情况2,3偷盗金额一定大于等于1的,因此,可以本题简化为在 198.打家劫舍 中的两个单排问题,在两种单排金额中取最大值,即可得到本地的解
动态规划做法:
定义 dp[i] 表示考虑抢劫 nums[0...i] 所能获得的最大收益(注意这里是闭区间) 由于不可以同时偷相邻的房屋,所以在当前位置为 i 房屋可盗窃的最大值要么就是 i-1 房屋可盗窃的最大值,要么就是 i-2 房屋可盗窃的最大值加上当前房屋的值,二者之间取最大值 所以状态转移方程为:dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]) 本题中对比 198 题不同在于封装动态规划函数,分别传入剔除第一个和最后一个房间的数组,求最大值即可 时间复杂度为 O(n)
var rob = function(nums) {
if (nums.length < 2) return nums[0];
var subrob = function(nums) {
if (nums.length < 2) return nums[0];
let temp = Math.max(nums[0],nums[1])
let dp = [nums[0], temp];
for (let i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1],dp[i - 2] + nums[i]);
}
return dp[nums.length - 1]
};
return Math.max(subrob(nums.slice(1)),subrob(nums.slice(0,nums.length - 1)))
};