Leetcode 337. House Robber III(python+cpp)

题目

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 0
            l = getdepth(node.left)
            r = getdepth(node.right)
            return max(l,r)+1
        def 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 0
        if d == 1:
            return root.val
        if d == 2:
            return max(sum(flatten[0]),sum(flatten[1]))
        dp = [0]*d
        dp[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 level
            curr_res[0] = max(left[0],left[1])+max(right[0],right[1])
            #rob curr_level
            curr_res[1] = node.val+left[0]+right[0]
            return curr_res
        ans = 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 current
        pair<int,int> curr_res{0,0};
        // rob current node, then it's child can not be robbed
        curr_res.first = node->val + left.second + right.second;
        // not rob current, then it's child can either be robbed or not robbed
        curr_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 0
            
            if (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)] = result
            else:
                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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值