Leetcode 337. House Robber III(python)

Leetcode 337. House Robber III

  • 题目
  • 错误解法
  • 正确解法:递归+动态规划

题目

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.
Leetcode 337. House Robber III(python)_第1张图片

错误解法

首先分享一下自己的错误解法。看完两个例子后,想当然的觉得对tree进行level traversal,然后求出每一层的sum,构成一个新的数组,对这个数组使用house robber I的方法就可以了,但实际上这种想法是错误的,比如下面这种情况就是不对的
Leetcode 337. House Robber III(python)_第2张图片
这个例子的正确答案是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));
    }
};

你可能感兴趣的:(Leetcode,动态规划)