Back to blog
Oct 13, 2024
14 min read

Evaluate Boolean Binary Tree

Evaluate boolean expression represented by a binary tree where leaves are 0/1 and internal nodes are OR/AND operations.

Difficulty: Easy | Acceptance: 82.40% | Paid: No Topics: Tree, Depth-First Search, Binary Tree

You are given the root of a full binary tree with the following properties:

Leaf nodes have either value 0 or 1, where 0 represents False and 1 represents True. Non-leaf nodes have either value 2 or 3, where 2 represents the boolean OR and 3 represents the boolean AND.

The evaluation of a node is as follows:

If the node is a leaf node, the evaluation is the value of the node, i.e., True or False. Otherwise, evaluate the node’s two children and apply the boolean operation of its value with the children’s evaluations.

Return the boolean result of evaluating the root node.

A full binary tree is a binary tree where each node has either 0 or 2 children.

Examples

Example 1:

Input: root = [2,1,3,null,null,0,1]
Output: true
Explanation: The AND node evaluates to False AND True = False.
The OR node evaluates to True OR False = True.
The root node evaluates to True, so we return true.

Example 2:

Input: root = [0]
Output: false
Explanation: The root node is a leaf node with value false, so we return false.

Constraints

The number of nodes in the tree is in the range [1, 1000].
0 <= Node.val <= 3
Every node has either 0 or 2 children.
Leaf nodes have a value of 0 or 1.
Non-leaf nodes have a value of 2 or 3.

Recursive DFS

Intuition Use post-order traversal to evaluate children first, then apply the operation at the current node.

Steps

  • If the node is a leaf (no children), return its boolean value.
  • Recursively evaluate the left and right subtrees.
  • Apply the operation (OR for value 2, AND for value 3) to the children’s results.
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 evaluateTree(self, root: Optional[TreeNode]) -> bool:
        if not root.left and not root.right:
            return root.val == 1
        
        left_val = self.evaluateTree(root.left)
        right_val = self.evaluateTree(root.right)
        
        if root.val == 2:
            return left_val or right_val
        else:  # root.val == 3
            return left_val and right_val

Complexity

  • Time: O(n) where n is the number of nodes
  • Space: O(h) where h is the height of the tree (recursion stack)
  • Notes: Clean and intuitive, but may cause stack overflow for very deep trees

Iterative DFS

Intuition Simulate the recursive approach using an explicit stack to avoid potential stack overflow.

Steps

  • Use a stack to perform post-order traversal with a visited flag.
  • Store computed values in a map for reuse.
  • Process nodes after their children have been evaluated.
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 evaluateTree(self, root: Optional[TreeNode]) -> bool:
        stack = [(root, False)]
        values = {}
        
        while stack:
            node, visited = stack.pop()
            
            if not node.left and not node.right:
                values[node] = node.val == 1
            elif visited:
                left_val = values[node.left]
                right_val = values[node.right]
                if node.val == 2:
                    values[node] = left_val or right_val
                else:
                    values[node] = left_val and right_val
            else:
                stack.append((node, True))
                stack.append((node.right, False))
                stack.append((node.left, False))
        
        return values[root]

Complexity

  • Time: O(n) where n is the number of nodes
  • Space: O(n) for the stack and values map
  • Notes: Avoids recursion stack overflow but uses more memory

BFS (Bottom-up)

Intuition Process nodes level by level from bottom to top, evaluating leaves first and propagating values up.

Steps

  • Perform level-order traversal to collect all levels.
  • Process levels from bottom to top.
  • For each node, if it’s a leaf, store its boolean value; otherwise, compute from children.
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
from collections import deque

class Solution:
    def evaluateTree(self, root: Optional[TreeNode]) -> bool:
        if not root.left and not root.right:
            return root.val == 1
        
        levels = []
        queue = deque([root])
        
        while queue:
            level_size = len(queue)
            level = []
            for _ in range(level_size):
                node = queue.popleft()
                level.append(node)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            levels.append(level)
        
        values = {}
        
        for level in reversed(levels):
            for node in level:
                if not node.left and not node.right:
                    values[node] = node.val == 1
                else:
                    left_val = values[node.left]
                    right_val = values[node.right]
                    if node.val == 2:
                        values[node] = left_val or right_val
                    else:
                        values[node] = left_val and right_val
        
        return values[root]

Complexity

  • Time: O(n) where n is the number of nodes
  • Space: O(n) for storing all levels and values
  • Notes: Intuitive level-by-level processing but uses more memory than DFS