198. House Robber
dp[i]: 考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]
若偷第i个房屋,dp[i] = dp[i-2] + nums[i]
若不偷,则dp[i] = dp[i-1]
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 1: return nums[0]
# 考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
return dp[-1]
213. House Robber II
和上题的区别是变成环了,首尾不能同时偷
所以分成三种情况:
- 范围不包含首尾
- 范围不包含头元素
- 范围不包含尾元素
但2/3都包含1,所以只要比较2、3的情况
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 1: return nums[0]
if len(nums) == 2: return max(nums[0], nums[1])
result1 = self.robRange(nums[: len(nums) - 1]) # 不包含尾元素
result2 = self.robRange(nums[1:]) # 不包含头元素
return max(result1, result2)
def robRange(self, nums):
dp = [0] * len(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1])
return dp[-1]
337. House Robber III
树形DP,dp数组为一个长度为2的数组,0: 不偷,1: 偷
利用后序遍历,通过递归左节点,得到左节点偷与不偷的金钱。通过递归右节点,得到右节点偷与不偷的金钱。最后得到‘中’节点不偷和偷时的最大值。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def rob(self, root: Optional[TreeNode]) -> int:
dp = self.robTree(root)
return max(dp[0], dp[1])
# 长度为2的数组,0:不偷,1:偷
def robTree(self, cur):
# 终止条件
if cur == None:
return [0, 0]
left = self.robTree(cur.left) # 左
right = self.robTree(cur.right) # 右
# 中
# 不偷cur,看左右孩子是否偷
value1 = max(left[0], left[1]) + max(right[0], right[1])
# 偷cur,就不能偷它的左右孩子
value2 = cur.val + left[0] + right[0]
return [value1, value2]