3道题目
198. 打家劫舍
213. 打家劫舍 II
337. 打家劫舍 III
解题理解
198
分两种情况讨论,当前偷则只能再偷第前二个,当前不偷则可以偷前一个。
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
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[len(nums) - 1]
213
与上一题相比,区别在于首尾相连,所以将首和尾分开考虑,即nums[首:-1]和nums[1:尾],并且可以重用上题的代码
class Solution:
def pre_rov(self, nums):
if len(nums) == 1:
return nums[0]
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[len(nums) - 1]
def rob(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
if len(nums) == 2:
return max(nums[0], nums[1])
res1 = self.pre_rov(nums[1:])
res2 = self.pre_rov(nums[:-1])
return max(res1, res2)
337
本题是一种树形动态规划的题,这种题的递归思路有些不太熟悉,还需要加强理解。
class Solution:
def traversal(self, root):
if not root:
return (0, 0)
left = self.traversal(root.left)
right = self.traversal(root.right)
# 不偷当前节点,只取子节点
children_val = max(left[0], left[1]) + max(right[0], right[1])
# 偷当前节点
val = root.val + left[0] + right[0]
return (children_val, val)
def rob(self, root: Optional[TreeNode]) -> int:
# dp数组为dp[0]不偷该节点,偷子节点的最大金额
# dp[1]为偷当前节点的最大金额
dp = self.traversal(root)
return max(dp)