LC198.打家劫舍:
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
if len(nums) == 1:
return nums[0]
dp = [0] * len(nums)
#考虑下标i以内的房屋,最大盗窃金额为dp[i]
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
#从dp[i]的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值
for i in range(2, len(nums)):
dp[i] = max(dp[i-2] + nums[i], dp[i-1])
#决定dp[i]的因素就是第i房间偷还是不偷
#如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i]
#如果不偷第i房间,那么dp[i] = dp[i - 1]
return dp[-1]
LC213.打家劫舍II:
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
val1 = self.robrange(nums[1:])
val2 = self.robrange(nums[:-1])
return max(val1, val2)
#在打家劫舍(1)的基础上,考虑两种情况,一是不偷第一间房,二是不偷最后一间房
def robrange(self, nums):
n = len(nums)
dp = [0] * n
dp[0] = nums[0]
for i in range(1, n):
if i == 1:
dp[i] = max(dp[i-1], nums[i])
else:
dp[i] = max(dp[i-2] + nums[i], dp[i-1])
return dp[-1]
LC337.打家劫舍III:
class Solution:
def rob(self, root: Optional[TreeNode]) -> int:
# dp数组(dp table)以及下标的含义:
# 1. 下标为 0 记录 **不偷该节点** 所得到的的最大金钱
# 2. 下标为 1 记录 **偷该节点** 所得到的的最大金钱
dp = self.traversal(root)
return max(dp)
# 要用后序遍历, 因为要通过递归函数的返回值来做下一步计算
def traversal(self, node):
# 递归终止条件,就是遇到了空节点,那肯定是不偷的
if not node:
return (0, 0)
left = self.traversal(node.left)
right = self.traversal(node.right)
# 不偷当前节点, 偷子节点
val_0 = max(left[0], left[1]) + max(right[0], right[1])
# 偷当前节点, 不偷子节点
val_1 = node.val + left[0] + right[0]
return (val_0, val_1)