問題描述
你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定乙個代表每個房屋存放金額的非負整數陣列,計算你不觸動警報裝置的情況下,一夜之內能夠偷竊到的最高金額。
示例 1:
輸入:[1,2,3,1]示例 2:輸出:4
解釋:偷竊1號房屋(金額=1),然後偷竊3號房屋(金額=3)。偷竊到的最高金額=1+3=4。
輸入:[2,7,9,3,1]遞迴方式解決這題讓計算小偷偷竊的最大金額,並且不能偷竊相鄰的兩家,這題一看就知道,不就是前幾天講的477,動態規劃解按摩師的最長預約時間嗎,只不過是換湯不換藥,基本原理還是一樣的。這題最簡單的一種解決方式就是使用動態規劃,可以參照第477題,就不在過多介紹。這裡來看另一種解決方式,遞迴。輸出:12
解釋:偷竊1號房屋(金額=2),偷竊3號房屋(金額=9),接著偷竊5號房屋(金額=1)。偷竊到的最高金額=2+9+1=12。
之前講426,什麼是遞迴,通過這篇文章,讓你徹底搞懂遞迴的時候提到遞迴的兩個重要要素,乙個是呼叫自己,乙個是必須要有終止條件,我們先來定義乙個函式
private
introbhelper
(int
nums,
int i)
他表示的是前i+1(i是從0開始的,0表示的是第1個房屋)個房屋所能偷竊到的最大值,那麼很明顯
private
introbhelper
(nums, i-
1)
表示的是前i個房屋所能偷竊到的最大值
private
introbhelper
(nums, i-
2)
表示的就是前i-1個房屋所能偷竊到的最大值因為第i-1個房屋和第i+1個房屋是不挨著的,所以如果偷完前i-1個房屋之後是可以再偷第i+1個房屋的。所以我們可以找到一種關係就是
private
introbhelper
(int
nums,
int i)
問題結束了嗎,當然沒有,因為我們知道遞迴必須要有終止條件,那麼終止條件是什麼呢,就是i小於0,也就是說沒有房屋可偷,最終**如下
public
introb
(int
nums)
private
introbhelper
(int
nums,
int i)
**優化之前講418,劍指 offer-斐波那契數列和356,青蛙跳台階相關問題的時候都提到過斐波那契數列的遞迴計算方式,遞迴的時候效率是很差的,因為**中包含大量的重複計算。這題也一樣,如果非要使用遞迴的方式解決,可以把計算的值先存起來,下次用的時候如果有就直接去取,如果沒有,再計算。
public
introb
(int
nums)
private
introbhelper
(int
nums,
int i, map
map)
//原理同時
if(map.
containskey
(i -1)
) last = map.
get(i -1)
;else
//偷上上家之前的還可以再偷當前這一家
int cur = lastlast + nums[i]
;//然後返回偷當前這一家和不偷當前這一家的最大值
return math.
max(last, cur)
;}
總結這題解法比較多,使用動態規劃和遞迴都是可以解決的,如果使用遞迴要注意**優化,否則當資料稍微多點,執行時間就會很長。
leetcode打家劫舍1,2,3(dp 遞迴)
leetcode打家劫舍1 題意 給定乙個陣列,相鄰的數字不能相加,其餘數字可以任意相加,問在次情況下最大和是多少 思路 理解題意後就能明白這道題的和最大和是個動態增長的過程而且依賴之前求出來的最大和,我們可以用dp來解決。dp的動態方程為dp i max dp i 2 nums i dp i 1 ...
演算法精解 遞迴 尾遞迴
書上這樣說的 尾遞迴呼叫是整個函式體中最後執行的語句且它的返回值不屬於表示式的一部分時,這個遞迴呼叫就是尾遞迴。什麼意思呢,就是說我們在寫遞迴函式的時候,最後執行的語句肯定是呼叫遞迴函式,並且在呼叫過程中沒有什麼加減乘除。我們拿基本遞迴來說,如下 int fact int n 看看上面,最後執行的語...
數值自乘(遞迴與非遞迴解)
如果m和n是正整數,那麼m n就是把m連乘n次,這是乙個很沒效率的方法。其實用分置 遞迴可以更有效地解決該問題!首先來看看我最初寫的程式吧 int r power int m,int n 其中用到的其實是非常樸素的遞迴方式,無法是將m n均分成兩部分,但是可能會存在奇偶等問題的干擾,所以乾脆將兩個遞...