The thief has found himself a new place for his thievery again. There is only one entrance to this area, called 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 form a binary tree. It will automatically contact the police if two directly-linked houses were broken into on the same night.
Given the root
of the binary tree, return the maximum amount of money the thief can rob without alerting the police.
Example 1:
Input: root = [3,2,3,null,3,null,1] Output: 7 Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
Example 2:
Input: root = [3,4,5,1,3,null,1] Output: 9 Explanation: Maximum amount of money the thief can rob = 4 + 5 = 9.
Constraints:
[1, 104]
.0 <= Node.val <= 104
This problem involves finding the maximum amount of money that can be robbed from houses arranged in a binary tree without robbing adjacent houses. The solution uses a depth-first search (DFS) with dynamic programming to efficiently solve this.
The core idea is to use a recursive DFS function that, for each node, returns two values:
rob
: The maximum amount of money that can be robbed including the current node.not_rob
: The maximum amount of money that can be robbed excluding the current node.The recursive function works as follows:
Base Case: If the node is null
, return (0, 0)
.
Recursive Step:
dfs
function on the left and right children to get their rob
and not_rob
values (la
, lb
, ra
, rb
).rob
for the current node: This is the sum of the current node's value, and the maximum amounts that can be robbed from the left and right subtrees without robbing the children ( lb + rb
).not_rob
for the current node: This is the maximum amount that can be robbed from the left and right subtrees, considering both options of robbing and not robbing the children (max(la, lb) + max(ra, rb)
).(rob, not_rob)
.After the DFS is complete, the maximum of the rob
and not_rob
values for the root node is returned as the final answer. This accounts for the possibility that the root node might or might not be robbed for the maximum gain.
# 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:
def dfs(root: Optional[TreeNode]) -> (int, int):
if root is None:
return 0, 0
la, lb = dfs(root.left)
ra, rb = dfs(root.right)
return root.val + lb + rb, max(la, lb) + max(ra, rb)
return max(dfs(root))
The other languages (Java, C++, Go, TypeScript) follow a very similar structure, reflecting the recursive nature of the DFS and the dynamic programming approach. They all achieve the same time and space complexities.