leetcode 打家劫舍問題

2021-10-04 08:42:22 字數 4454 閱讀 4802

題目:你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。

給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。

分析:dp[i]定義:nums[0,i]的最多的金額集合;

狀態轉移方程:dp[i] = max(dp[i-1],dp[i-2]+nums[i])

base case: dp[0] = i,dp[1] =max(dp[0],dp[1])

def

rob(self, nums)

:"""

:type nums: list[int]

:rtype: int

"""n =

len(nums)

if n ==1:

return nums[0]

if n==0:

return

0 dp =

[val for val in nums]

if dp[0]

>dp[1]

: dp[1]

= dp[0]

for i in

range(2

,n):

dp[i]

=max

(dp[i-2]

+nums[i]

,dp[i]

,dp[i-1]

)return dp[-1

]

題目:你是乙個專業的小偷,計畫偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都圍成一圈,這意味著第乙個房屋和最後乙個房屋是緊挨著的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。

給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。

**分析:**相比打家劫舍1 ,增加了乙個限制條件,就是,首尾元素不能同時出現。

dp 問題:

dp[i]定義:nums[0,i]的最多的金額集合;

分兩種情況:1.帶首元素的最優集合,2.帶尾元素的最優集合;3.首尾元素都不帶的最優集合。

狀態轉移方程:dp[i] = max(dp[i-1],dp[i-2]+nums[i])

base case: dp[0] = i,dp[1] =max(dp[0],dp[1])

『』』

def

rob_range

(self,arr,left,right)

: arr = arr[left:right]

n =len(arr)

if n==0:

return

0if n==1:

return arr[0]

dp =

[val for val in arr]

if dp[0]

> dp[1]

: dp[1]

= dp[0]

for i in

range(2

,n):

dp[i]

=max

(dp[i-2]

+arr[i]

,dp[i]

,dp[i-1]

)return dp[-1

]def

rob(self,nums)

: n =

len(nums)

if n ==1:

return nums[0]

if n ==0:

return

0 res1 = self.rob_range(nums,

1,n-1)

# 第一家和最後一家都不偷

res2= self.rob_range(nums,

1,n)

#第一家不偷

res3 = self.rob_range(nums,

0,n-1)

#最後一家不偷

return

max(

[res1,res2,res3]

)

題目:在上次打劫完一條街道之後和一圈房屋後,小偷又發現了乙個新的可行竊的地區。這個地區只有乙個入口,我們稱之為「根」。 除了「根」之外,每棟房子有且只有乙個「父「房子與之相連。一番偵察之後,聰明的小偷意識到「這個地方的所有房屋的排列類似於一棵二叉樹」。 如果兩個直接相連的房子在同一天晚上被打劫,房屋將自動報警。

計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。

解法一:遞迴實現,重複子問題,先找到最小規模的問題,就是最優子結構;

使用爺爺-兩個孩子-4個孫子 小偷家族來說明問題,這個家族的每個成員偷到的錢就是對應二叉樹結點的值。

問題的目標就是在這棵二叉樹能偷到最多的錢。

可分為兩種情況:4個孫子偷的錢 + 爺爺的錢 vs 兩個兒子偷的錢

method1 = root.val + rob(root.left.left) + rob(root.left.right) +rob(root.right.left) + rob(root.right.right)

method2 = rob(root.left) + root(root.right)

時間複雜度:o(n*n)

def

robtree

(root):

dic =

dict()

return rob(root,dic)

defrob

(root,dic)

:if root ==

none

:return

0if root in dic.keys():

return dic[root]

res = root.val

if root.left:

res += rob(root.left.left)

+rob(root.left.right)

if root.right:

res += rob(root.right.left)

+ rob(root.right.right)

return

max(res,rob(root.left)

+rob(root.right)

)

leetcode python 超出時間限制

解法2:使用dp table-備忘錄

public

introb

(treenode root)

public

introbinternal

(treenode root, hashmap

memo)

if(root.right != null)

int result = math.

max(money,

robinternal

(root.left, memo)

+robinternal

(root.right, memo));

memo.

put(root, result)

;return result;

}

分析:不用備忘錄,我們使用乙個大小為2的陣列來表示 int res = new int[2] 0代表不偷,1代表偷。

換一種方法定義問題,每個節點可以選擇偷偷或者不偷兩種狀態,根據題目意思,相鄰不能偷,所以,當前節點擊擇偷時,那麼兩個孩子節點就不能選擇偷了;當前節點擊擇不偷時,兩個孩子節點只需要拿最多的錢出來就行(兩個孩子節點偷不偷沒關係)

單個節點狀態轉移方程如下:

root[0] = math.max(rob(root.left)[0], rob(root.left)[1]) + math.max(rob(root.right)[0], rob(root.right)[1])

root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;

def

rob(root)

: res = robtree(root)

return

max(res)

defrobtree

(root)

:if root ==

none

:return[0

,0] left = robtree(left)

right = robtree(right)

rob = left[0]

+right[0]

+ root.val

not_rob =

max(left[0]

,left[1]

)+max(right[0]

,right[1]

)return

[not_rob,rob]

現在偷家都要講究演算法了,哈哈哈!

LeetCode打家劫舍問題

打家劫舍i 簡單的dp 設定兩個陣列 f i 代表必偷第i個,g i 代表不偷第i個 class solution return max f n g n 打家劫舍ii 這裡跟第一題最大的區別在於第一家跟第n家不能同時偷 要麼偷1不偷n 要麼偷n不偷n 要麼都不偷 所以分類討論 第一種不選第一家 f ...

LeetCode 打家劫舍問題

q 你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。示例 1 輸入...

打家劫舍問題 LeetCode198 213

你是乙個專業的小偷,計畫偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。示例 1 輸入 1...