一、前言
每天五分鐘,看懂一道簡單、中等難度的算法題
瘋狂學習python中,每天持續更新
書山有路勤爲徑,學海無涯苦作舟;與君初相識,猶如故人歸。
二、題目
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數數組,計算你 不觸動警報裝置的情況下 ,一夜之內能夠偷竊到的最高金額。
示例一:
輸入: [1,2,3,1]
輸出: 4
解釋: 偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3)。
偷竊到的最高金額 = 1 + 3 = 4 。
實例二:
輸入: [2,7,9,3,1]
輸出: 12
解釋: 偷竊 1 號房屋 (金額 = 2), 偷竊 3 號房屋 (金額 = 9),接着偷竊 5 號房屋 (金額 = 1)。
偷竊到的最高金額 = 2 + 9 + 1 = 12 。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/house-robber
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
三、解答思路
判斷條件:
-
當房間數爲 H = 1 時:偷盜 K 房間即可獲得最大收益 ,公式爲: S1 = H1
-
當房間數爲 H = 2 時: S2 =max( S1 ,H2)
-
當房間數爲 H= 3時:S3 = max(s1+H3 , s2)
-
當房間數爲 H =4 時:S4=max(S2+H4,S3)
遞推公式:
邊界條件:
注:當房間數爲0時,條件不成立。
四、相關知識點
4.1 動態規劃算法思想
動態規劃算法通常用於求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每一個解都對應於一個值,我們希望找到具有最優值的解。
例子:
一個原始問題,可以分爲多個子問題,多個子問題結果可能是重複的,爲了方便調用,便於計算,它會保存已有結果,再遇到相同的子問題直接調用保存的結果。
相同子問題怎麼產生的?
解:我們先求F(5)的解,如下,以二叉樹的結構表示
通過二叉樹,我們注意到,F(n)是通過計算它的兩個重疊子問題 F(n-1)和F(n-2)的形式來表達的,所以,可以設計一張表填入n+1個F(n)的值。通過下面的表會發現:後一個數等於前面兩個數的和。(這就是著名的斐波那契數)
五、代碼實例
"""
你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。
給定一個代表每個房屋存放金額的非負整數數組,計算你 不觸動警報裝置的情況下 ,一夜之內能夠偷竊到的最高金額。
示例 1:
輸入: [1,2,3,1]
輸出: 4
解釋: 偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3)。
偷竊到的最高金額 = 1 + 3 = 4 。
示例 2:
輸入: [2,7,9,3,1]
輸出: 12
解釋: 偷竊 1 號房屋 (金額 = 2), 偷竊 3 號房屋 (金額 = 9),接着偷竊 5 號房屋 (金額 = 1)。
偷竊到的最高金額 = 2 + 9 + 1 = 12 。
"""
from typing import List
nums = [2, 11, 18, 15, 1]
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums: # 如果房間數爲空,則收益爲0
return 0
if len(nums) == 1: # 只有一間房,這就是最大收益
return nums[0]
dp = [0, 0] # n必須大於2,套用公式計算的話,會超出索引範圍,假設增加兩個空房間,來進行對比
dp.extend(nums) # 列表相加,得到[0, 0 ,2, 11, 18, 15, 1]
for i in range(2, len(dp)):
# dp[i] 也可以看出前幾個房間的收益,最後一個房間收益是前面累計的和。
dp[i] = max(dp[i-1], dp[i-2]+dp[i])
return dp[-1] # 取列表最後一個值
if __name__ == '__main__':
obj = Solution()
print(obj.rob(nums))
總結分析:
"""
dp[i] 也可以看做是賬本,記錄着前幾個房間盜竊的收益
通過循環看到賬本每次變動情況,直觀瞭解項目運行過程
[0, 0, 2, 11, 18, 15, 1]
[0, 0, 2, 11, 18, 15, 1]
[0, 0, 2, 11, 20, 15, 1]
[0, 0, 2, 11, 20, 26, 1]
[0, 0, 2, 11, 20, 26, 26]
也就是最後一次賬本記錄的收益,是前幾次盜竊的總值
"""