繼續(xù)我們的每日算法題系列,有時候你不知道干嘛的時候來上兩道算法題,真香~
話不多說,來看看今天的題目,感覺還是比較有意思的:
題目描述
你是一個專業(yè)的小偷,計劃偷竊沿街的房屋。每間房內(nèi)都藏有一定的現(xiàn)金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統(tǒng),如果兩間相鄰的房屋在同一晚上被小偷闖入,系統(tǒng)會自動報警。
給定一個代表每個房屋存放金額的非負(fù)整數(shù)數(shù)組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。
示例1:
輸入: [1,2,3,1]
輸出: 4
解釋: 偷竊 1 號房屋 (金額 = 1) ,然后偷竊 3 號房屋 (金額 = 3)。
偷竊到的最高金額 = 1 + 3 = 4 。
示例1:
輸入: [2,7,9,3,1]
輸出: 12
解釋: 偷竊 1 號房屋 (金額 = 2), 偷竊 3 號房屋 (金額 = 9),接著偷竊 5 號房屋 (金額 = 1)。
偷竊到的最高金額 = 2 + 9 + 1 = 12 。
這道題目是一道很典型的 “動態(tài)規(guī)劃” 類算法題目,LZ我在動態(tài)規(guī)劃這類題目上還是偏薄弱,動態(tài)規(guī)劃的精髓就是狀態(tài)轉(zhuǎn)移方程,通常你遇到這類題目的時候,基本上都是 “找最優(yōu)解”,“重疊子問題”,一般來說一個大的問題是可以拆成一個個子問題,下面我們來在線分析一下。
解題思路
首先我們來拆分問題,拆成最簡單的來看:
1、當(dāng)只有1間房的時候,我們沒有選擇,只能選擇搶劫這間房;
2、當(dāng)有兩間房的時候,我們可以比較哪間房里面的錢多,搶劫錢多的房間就好了;
3、當(dāng)有三間房的時候,有兩種方案,搶1,3號房間/搶2號房間的,比較一下哪種方案多;
4、當(dāng)有四間房的時候,因為我們已經(jīng)知道了1,2,3間房時能獲取到的最大金額,所以我們只需要將搶第四間房的金額數(shù)加上搶第二間房能獲取到的最大金額數(shù)來和第三間房進(jìn)行比較,取最大值就好了。
相信寫到這里大家應(yīng)該就能看出來狀態(tài)轉(zhuǎn)移方程是什么了吧,當(dāng)我們搶劫第 i
間房的時候,我們需要比較一下第 i-2
間房所能獲取到的最大金額數(shù)加上當(dāng)前房間的金額數(shù)和第 i-1
間房所能獲取到的最大金額數(shù)哪個大;我們用一個數(shù)組來保存搶劫金額的最大數(shù),于是就有了,f[n] = Math.max(f[n-2] + money[n], f[n-1])
題解
public int rob(int[] nums) {
if (null == nums || nums.length == 0) {
return 0;
}
int len = nums.length;
if (len == 1) {
return nums[0];
}
if (len == 2) {
return Math.max(nums[0], nums[1]);
}
//上述判斷是將最簡單的幾種情況先計算好,也是為了初始化momey[0] 和 money[1]
// 定義一個數(shù)組,用來保存打劫 0 - (len-1) 家最大能打劫到的金額數(shù)
int[] money = new int[len];
money[0] = nums[0];
money[1] = Math.max(nums[0], nums[1]);
for (int i = 2; i < len; i++) {
money[i] = Math.max(money[i - 2] + nums[i], money[i - 1]);
}
return money[len - 1];
}