Skip to content

337. House Robber III

Edited by Charles

Medium · Python · Dynamic Programming

Problem

Read the original problem on LeetCode.

The official page contains the problem statement, examples, and constraints.

Explanation, examples & other approaches

Core idea

  • This is a Tree DP problem.
  • For each node, there are only two states:
  • Rob this node.
  • Do not rob this node.
  • Compute these two states for every node using postorder traversal.

Original study notes follow, including intermediate snippets and earlier attempts.

Idea

  • This is a Tree DP problem.
  • For each node, there are only two states:
    • Rob this node.
    • Do not rob this node.
  • Compute these two states for every node using postorder traversal.

DP Definition

For each node, return:

[rob, notRob]

  • rob = maximum money if the current node is robbed.
  • notRob = maximum money if the current node is not robbed.

Base Case

If the node is None:

return [0, 0]

Transition

Rob current node

If the current node is robbed, its children cannot be robbed.

rob = node.val + left[1] + right[1]

Do not rob current node

If the current node is not robbed, each child can be either robbed or skipped.

notRob = max(left) + max(right)

Why postorder traversal?

The DP state of the current node depends on the DP states of its children.

Therefore, compute the left and right subtrees first, then compute the current node.

(Postorder: Left → Right → Node)

Final Answer

After processing the root:

return max(root.rob, root.notRob)

Complexity

Time: O(n)

Space: O(h)

  • n = number of nodes
  • h = height of the tree (recursion stack)
Study record
Field Value
Attempts 1
Mastery ❚

Python solution

# 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: Optional[TreeNode]) -> int:
        res = self.traverse(root)
        return max(res)

    def traverse(self, node):
        if not node:
            return [0, 0] # [偷,不偷]

        left = self.traverse(node.left)
        right = self.traverse(node.right)

        # 偷当前节点, 不偷子节点
        robVal = node.val + left[1] + right[1]
        # 不偷当前节点, 偷子节点
        noVal = max(left) + max(right)

        return [robVal, noVal]

Back to Day 34 Dynamic Programming VII · All Algorithm notes