首先先给出题目的地址。https://leetcode-cn.com/problems/house-robber-iii/(https://leetcode-cn.com/problems/house-robber-iii/)
首先是简单版的打家劫舍,这是题是一维dp,考虑状态方程,dp[i]是到i为止,获取最大的收益,那么dp[i]就等于他这次没偷,第i-1次的最大收益和这次偷了的收益加上第i-2次的最大收益,
即dp[i]=max(dp[i-1],dp[i-2]+nums[i]),显然dp[0]=nums[0],dp[1]=max(nums[0],nums[1]).python代码如下:
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums:
return 0
if len(nums)==1:
return nums[0]###前面是特殊的情况处理
dpc = [0]* len(nums)
dpc[0] = nums[0]
dpc[1] = max(nums[1],nums[0])###赋初值
for i in range(2,len(nums)):
dpc[i] = max(dpc[i-2]+nums[i],dpc[i-1])###状态转移方程
return dpc[-1]
升级版打家劫舍,和上题一样,就是多了个首尾也算相邻的。可以考虑去头去尾,分别做一次打家劫舍,然后去最大值就OK了。
class Solution:
def rob(self, nums: List[int]) -> int:
if not nums :
return 0
if len(nums)==1:
return nums[0]
if len(nums)==2:
return max(nums)
def get(nums):
dpc = [0]*(len(nums))
dpc[0] ,dpc[1] = nums[0],max(nums[0],nums[1])
for i in range(2,len(nums)):
dpc[i] = max(dpc[i-2]+nums[i],dpc[i-1])
return dpc
return max(get(nums[1:])[-1],get(nums[:-1])[-1])####返回两次的最大值
终极版打家劫舍问题。
这是一道树形dp的题目,意思还是和之前一样相邻位置不能同时偷盗。
我们可以这样考虑,考虑某个节点可以取得的最大值,可以将其分为当前节点p,孩子节点h,和孩子节点的孩子节点s,那么对于p节点来说他的最大值有哪些可能呢?
1,当前节点p选择,那么p点的最大值就是当前节点和其左右孩子节点的孩子节点(也就是所有孙子节点)的最大值。
2,当前节点p不选择,那么他的最大值就有些复杂了。
2-1,首先左右孩子节点的都选择的最大之和。
2-2,其次是左右孩子都不选的最大之和
2-3 然后就是左孩子选择右孩子不选之和
2-3 最后就是左孩子不选右孩子选择之和这四种情况。
代码还是比较简单的。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
self.ans = 0
def rob(self, root: TreeNode) -> int:
def rob2(root):
if not root:
return (0,0)
nl,l = rob2(root.left)
nr,r = rob2(root.right)
my = root.val
nchoose = max(l+r,nl+nr,l+nr,nl+r)####当前节点不选的最大值就是四种情况的最大值
choose = nl+nr+my ####当前节点选择的最大值就是左右孩子都选的最大值
self.ans = max(self.ans,nchoose,choose)
return (nchoose,choose) ####每次返回两个值,一个是当前节点选择取得的最大的值,一个是当前节点不选取得的最大值
rob2(root)
return self.ans
这道题目理解之后感觉还是不算特别难的。