「動態規劃」「leetcode」 213.打家劫舍 II

原題

你是一個專業的小偷,計劃偷竊沿街的房屋,每間房內都藏有必定的現金。這個地方全部的房屋都圍成一圈,這意味着第一個房屋和最後一個房屋是緊挨着的。同時,相鄰的房屋裝有相互連通的防盜系統,若是兩間相鄰的房屋在同一夜被小偷闖入,系統會自動報警。數組

給定一個表明每一個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的狀況下,可以偷竊到的最高金額。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

image

推導狀態轉移方程的過程,這裏就不在贅述,不明白的同窗能夠看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])
};


複製代碼
相關文章
相關標籤/搜索