你是一個專業的小偷,計劃偷竊沿街的房屋,每間房內都藏有必定的現金。這個地方全部的房屋都圍成一圈,這意味着第一個房屋和最後一個房屋是緊挨着的。同時,相鄰的房屋裝有相互連通的防盜系統,若是兩間相鄰的房屋在同一夜被小偷闖入,系統會自動報警。數組
給定一個表明每一個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的狀況下,可以偷竊到的最高金額。bash
示例 1:post
輸入: [2,3,2]
輸出: 3
解釋: 你不能先偷竊 1 號房屋(金額 = 2),而後偷竊 3 號房屋(金額 = 2), 由於他們是相鄰的。
複製代碼
示例 2:ui
輸入: [1,2,3,1]
輸出: 4
解釋: 你能夠先偷竊 1 號房屋(金額 = 1),而後偷竊 3 號房屋(金額 = 3)。
偷竊到的最高金額 = 1 + 3 = 4 。
複製代碼
本題的主要思路同198.打家劫舍題相似。因爲題目的限制,須要注意的是,第一家和最後一家不能同時搶spa
推導狀態轉移方程的過程,這裏就不在贅述,不明白的同窗能夠看198題的題解。code
我在思考🤔這道題目的時候,曾經陷入了一個思惟的誤區認爲,cdn
最高金額 = max(最高金額 - 第一家的金額, 最高金額 - 最後一家的金額) if 最高金額包含了第一家以及最後一家
blog
爲此,我浪費了一個小時的時間。在反覆試錯過程當中發現了思考方向的錯誤,下面是一個反例get
const nums = [2,2,4,3,2,5]
// 最大值爲11,可是首尾成環
const max = 2 + 4 + 5
// max - 2 === 9 或者 max - 5 == 6 都不是最大值
// 若是在避免成環的狀況下,最大值
const max = 2 + 3 + 5
複製代碼
經過這個反例可知,咱們在不能簡單粗暴的去掉頭尾,須要在去掉頭或者尾時,從新計算nums的最優解。it
/** * @param {number[]} nums * @return {number} */
var rob = function (nums) {
if (nums.length === 0) {
return 0
}
if (nums.length === 1) {
return nums[0]
}
const getDp = (nums) => {
const dp = []
for (let i = 0; i < nums.length; i++) {
let m = dp[i - 2] === undefined ? 0 : dp[i - 2]
m = m + nums[i]
let n = dp[i - 1] === undefined ? 0 : dp[i - 1]
if (m > n) {
dp[i] = m
} else {
dp[i] = n
}
}
return dp
}
const nums1 = [...nums]
nums1.shift()
const nums2 = [...nums]
nums2.pop()
// 去頭後的最好結果
const dp1 = getDp(nums1)
// 去尾後的最好結果
const dp2 = getDp(nums2)
return Math.max(dp1[dp1.length - 1], dp2[dp2.length - 1])
};
複製代碼