Taro Logo

Binary Tree Cameras

Medium
1 views
2 months ago

You are given the root of a binary tree. We install cameras on the tree nodes where each camera at a node can monitor its parent, itself, and its immediate children. Return the minimum number of cameras needed to monitor all nodes of the tree.

For example:

Input: root = [0,0,null,0,0] Output: 1 Explanation: One camera is enough to monitor all nodes if placed as shown.

Input: root = [0,0,null,0,null,0,null,null,0] Output: 2 Explanation: At least two cameras are needed to monitor all nodes of the tree. The above image shows one of the valid configurations of camera placement.

Constraints:

The number of nodes in the tree is in the range [1, 1000]. Node.val == 0

Sample Answer
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def minCameraCover(self, root: TreeNode) -> int:
        # 0: Not covered, need a camera at parent
        # 1: Covered, but no camera here
        # 2: Has a camera

        self.camera_count = 0

        def dfs(node):
            if not node:  # Null node is considered covered
                return 1

            left_state = dfs(node.left)
            right_state = dfs(node.right)

            if left_state == 0 or right_state == 0:
                # If any child needs a camera, install one here
                self.camera_count += 1
                return 2

            if left_state == 2 or right_state == 2:
                # If any child has a camera, this node is covered
                return 1

            # Otherwise, this node is not covered
            return 0

        # Handle the root node
        if dfs(root) == 0:
            self.camera_count += 1

        return self.camera_count

Explanation:

The problem requires finding the minimum number of cameras to cover all nodes in a binary tree, where a camera at a node covers its parent, itself, and its immediate children.

Naive Approach (Not Implemented):

A naive approach might involve trying all possible camera placements and finding the minimum number of cameras that cover all nodes. This would be highly inefficient due to the exponential number of possible placements.

Optimal Approach:

The optimal approach uses a depth-first search (DFS) and a state-based strategy to determine the placement of cameras. Each node can be in one of three states:

  • 0 (Not Covered): The node is not covered by any camera.
  • 1 (Covered): The node is covered by a camera, but the node itself does not have a camera.
  • 2 (Has Camera): The node has a camera.

The DFS function recursively traverses the tree, determining the state of each node based on the states of its children. The algorithm prioritizes covering nodes with cameras as low in the tree as possible.

  1. Base Case: If the node is None (null), it is considered covered (state 1).
  2. Recursive Step:
    • Recursively determine the states of the left and right children.
    • If either child is in state 0 (not covered), install a camera at the current node (increment camera_count and set the current node's state to 2).
    • If either child has a camera (state 2), the current node is covered (state 1).
    • Otherwise, the current node is not covered (state 0).
  3. Root Handling: After the DFS, if the root node is in state 0 (not covered), install a camera at the root.

Example:

Consider the tree [0,0,null,0,0]. The algorithm would work as follows:

  1. The DFS starts at the root (0).
  2. The left child is 0, and the right child is None (covered, state 1).
  3. The left child's children are both 0. Since both are not covered (state 0), a camera is placed at the left child, and the camera_count becomes 1. The left child's state becomes 2.
  4. Since the left child has a camera, the root is now covered (state 1).
  5. After the DFS, the root is covered, so no additional camera is needed.
  6. The function returns camera_count, which is 1.

Big(O) Runtime Analysis:

The runtime complexity is O(N), where N is the number of nodes in the tree. The DFS function visits each node once.

Big(O) Space Usage Analysis:

The space complexity is O(H), where H is the height of the tree, due to the recursive call stack. In the worst case (skewed tree), H can be equal to N, resulting in O(N) space complexity. In the average case (balanced tree), H is log(N), resulting in O(log N) space complexity.

Edge Cases:

  • Empty Tree: If the tree is empty (root is None), no cameras are needed, and the function should return 0.
  • Single Node Tree: If the tree has only one node, a camera is needed at the root, and the function should return 1.
  • Skewed Tree: The algorithm should handle skewed trees (where all nodes are on one side) efficiently.
  • Balanced Tree: The algorithm should handle balanced trees efficiently.