Leetcode 337. House Robber III
- 题目
- 错误解法
- 正确解法:递归+动态规划
- 解法3:dfs+memorization
题目
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the “root.” Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that “all houses in this place forms a binary tree”. It will automatically contact the police if two directly-linked houses were broken into on the same night. Determine the maximum amount of money the thief can rob tonight without alerting the police.
错误解法
首先分享一下自己的错误解法。看完两个例子后,想当然的觉得对tree进行level traversal,然后求出每一层的sum,构成一个新的数组,对这个数组使用house robber I的方法就可以了,但实际上这种想法是错误的,比如下面这种情况就是不对的
这个例子的正确答案是7,而用我的错误方法求出来是6,关键在于没有仔细读题目中的这句话:It will automatically contact the police if two directly-linked houses were broken into on the same night. 所以其实这边的3和4这两个节点不是directly-linked的
错误代码
class Solution(object):def rob(self, root):""":type root: TreeNode:rtype: int"""def getdepth(node):if not node:return 0l = getdepth(node.left)r = getdepth(node.right)return max(l,r)+1def traversal(node,level):if not node:return flatten[level].append(node.val)traversal(node.left,level+1)traversal(node.right,level+1)d = getdepth(root)flatten = [[] for _ in range(d)]traversal(root,0)if not root:return 0if d == 1:return root.valif d == 2:return max(sum(flatten[0]),sum(flatten[1]))dp = [0]*ddp[0] = sum(flatten[0])dp[1] = max(sum(flatten[0]),sum(flatten[1]))for i in range(2,d):dp[i] = max(sum(flatten[i])+dp[i-2],dp[i-1])return dp[-1]
正确解法:递归+动态规划
这道题目归结为一句话来说就是:本节点+孙子及更深节点 vs 子节点+重孙更深节点
正确的思路为,在递归中进行动态规划的过程。在递归的每一层返回两个值,前一个值代表对当前node不进行rob的结果,后一个值代表对当前node进行rob和不进行rob中的最大值.
python代码如下:
# 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: TreeNode) -> int:def dfs(node):if not node: return [0,0]rob_left = dfs(node.left)rob_right = dfs(node.right)not_robcurr = rob_left[1]+rob_right[1]robcurr = node.val + rob_left[0] +rob_right[0]return [not_robcurr,max(not_robcurr,robcurr)]return dfs(root)[1]
另外一种解法也是类似的想法,不过利用了动态规划的思想
#not rob current node
case0 = max(rob_leftchild,notrob_leftchild) + max(rob_rightchild,notrob_rightchild)
#rob current node
case1 = node.val + notrob_leftchild + notrob_rightchild
代码:
class Solution(object):def rob(self, root):""":type root: TreeNode:rtype: int"""def robchild(node):if not node:return [0,0]left = robchild(node.left)right = robchild(node.right)curr_res = [0,0]#not rob curr levelcurr_res[0] = max(left[0],left[1])+max(right[0],right[1])#rob curr_levelcurr_res[1] = node.val+left[0]+right[0]return curr_resans = robchild(root)return max(ans)
时间复杂度:O(N), N为节点的个数
空间复杂度:O(H),H为树的深度
C++版本代码如下:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:int rob(TreeNode* root) {
return dfs(root).second;}pair<int,int> dfs(TreeNode* node){
// 注意make_pair在这边的用法if (!node) return make_pair(0,0);// auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型auto rob_left = dfs(node->left);auto rob_right = dfs(node->right);int not_robcurr = rob_left.second + rob_right.second;int robcurr = node->val + rob_left.first + rob_right.first;return make_pair(not_robcurr,max(not_robcurr,robcurr));}
};
C++版本
class Solution {
public:int rob(TreeNode* root) {
return max(dfs(root).first,dfs(root).second);}pair<int,int> dfs(TreeNode* node){
if (!node) return {
0,0};auto left = dfs(node->left);auto right = dfs(node->right);// first ele represent rob current node, second not rob currentpair<int,int> curr_res{
0,0};// rob current node, then it's child can not be robbedcurr_res.first = node->val + left.second + right.second;// not rob current, then it's child can either be robbed or not robbedcurr_res.second = max(left.first,left.second) + max(right.first,right.second);return curr_res; }
};
解法3:dfs+memorization
class Solution:def rob(self, root: TreeNode) -> int:def dfs(node,parent_rob):if not node:return 0if (node,parent_rob) in memo:return memo[(node,parent_rob)]if parent_rob:result = dfs(node.left,False) + dfs(node.right,False)memo[(node,parent_rob)] = resultelse:rob = node.val + dfs(node.left,True) + dfs(node.right,True)not_rob = dfs(node.left,False) + dfs(node.right,False)memo[(node,parent_rob)] = max(rob,not_rob)return memo[(node,parent_rob)]memo = {
}return dfs(root,False)