LeetCode 198. 打家劫舍 --DP

198. 打家劫舍

問題描述:

你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有必定的現金,影響你偷竊的惟一制約因素就是相鄰的房屋裝有相互連通的防盜系統,若是兩間相鄰的房屋在同一夜被小偷闖入,系統會自動報警。算法

給定一個表明每一個房屋存放金額的非負整數數組,計算你 不觸動警報裝置的狀況下 ,一晚上以內可以偷竊到的最高金額。數組

image.png

題解

動態規劃(Dynamic Programming, DP)

  • 動態規劃只能應用於有最優 子結構的問題。最優子結構的意思是局部最優解能決定全局最優解(對有些問題這個要求並不能徹底知足,故有時須要引入必定的近似)。markdown

  • 簡單地說,問題可以分解成子問題來解決spa

  • 通俗一點來說,動態規劃和其它遍歷算法(如深/廣度優先搜索)都是將原問題拆成多個子問題而後求解,他們之間最本質的區別是,動態規劃保存子問題的解,避免重複計算3d

  • 解決動態規劃問題的關鍵是找到狀態轉移方程,這樣咱們能夠通計算和儲存子問題的解來求解最終問題code

  • 同時,咱們也能夠對動態規劃進行空間壓縮,起到節省空間消耗的效果。orm

  • 在一些狀況下,動態規劃能夠當作是帶有狀態記錄(memoization)的優先搜索it

  • 動態規劃是自下而上的,即先解決子問題,再解決父問題;io

  • 而用帶有狀態記錄的優先搜索自上而下的,即從父問題搜索到子問題,若重複搜索到同一個子問題則進行狀態記錄,防止重複計算。table

  • 若是題目需求的是最終狀態,那麼使用動態搜索比較方便;

  • 若是題目須要輸出全部的路徑,那麼使用帶有狀態記錄的優先搜索會比較方便。

分析:

定義數組 dp,dp[i]到表示第 i 個房子時,能夠搶劫的最大數量。

這時候有兩種選擇,一不搶劫這個房子,累計金額爲dp[i-1];二搶,累計的最大金額dp[i-2],由於咱們不

可以搶劫第 i-1 個房子,不然會觸發警報機關,狀態轉移方程爲 dp[i] = max(dp[i-1],

nums[i] + dp[i-2])。

/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function(nums) {
   if(!nums.length) return 0;
   if(nums.length === 1) return nums[0]
   if(nums.length === 2) return Math.max(nums[0], nums[1]); 
   let n = nums.length;
   let dp = [];
   dp[0] = nums[0];
   dp[1] = Math.max(Math.max(nums[0], nums[1]));
   for(let i = 2; i < n; i++) {
       dp[i] = Math.max(dp[i-1], nums[i] + dp[i-2]);
   }
   return dp[n-1];
};

複製代碼

空間壓縮

var rob = function(nums) {
   if(!nums.length) return 0;
   if(nums.length === 1) return nums[0]
   if(nums.length === 2) return Math.max(nums[0], nums[1]); 
   let n = nums.length;
   // O(n)--> O(1)
   let pre2 = nums[0], pre1 = Math.max(Math.max(nums[0], nums[1])), cur;
   for(let i = 2; i < n; i++) {
       cur = Math.max(pre1, nums[i] + pre2);
       pre2 = pre1;
       pre1 = cur;
   }
   return cur;
};
複製代碼
相關文章
相關標籤/搜索