Find the Product of All Leaf Nodes in a Binary Tree
Step-by-step guide to finding the product of all leaf nodes in a binary tree using recursive DFS. Python, Java, and C++ code with O(n) complexity analysis.
The product of all leaf nodes in a binary tree is computed in a single DFS pass: visit every node, check whether it is a leaf, and multiply its value into a running product.
The original article on this topic was 163 words with no explanation. This rewrite covers the full problem: definition, algorithm, working code in three languages, complexity, and the edge cases that trip up candidates in placement rounds at TCS, Infosys, Wipro, and Cognizant.
What Is a Leaf Node
A binary tree is a data structure where each node holds a value and has at most two children, called left and right. A leaf node is any node whose left child and right child are both null. It has no descendants. It marks the end of every root-to-leaf path.
Consider this tree:
1
/ \
2 3
/ \ / \
8 5 6 9
The leaf nodes here are 8, 5, 6, and 9. The internal nodes are 1, 2, and 3.
The product of the leaf nodes, computed step by step:
- 8 × 5 = 40
- 40 × 6 = 240
- 240 × 9 = 2160
Final product: 2160. This is the expected output for any correct implementation on this tree.
The Algorithm: DFS with Product Accumulation
The algorithm is a depth-first traversal with one conditional check per node.
The recursion contract has three cases:
- Null node: return 1 (the multiplicative identity — multiplying by 1 leaves any accumulated product unchanged).
- Leaf node: return the node’s value directly.
- Internal node: recurse into left and right subtrees, then return the product of the two results.
Pseudocode:
function leafProduct(node):
if node is null:
return 1
if node.left is null AND node.right is null:
return node.data
leftResult = leafProduct(node.left)
rightResult = leafProduct(node.right)
return leftResult * rightResult
Step-by-step trace on the example tree:
- Call
leafProduct(1). Node 1 is internal. Recurse left and right. - Call
leafProduct(2). Node 2 is internal. Recurse left and right. - Call
leafProduct(8). Node 8 is a leaf. Return 8. - Call
leafProduct(5). Node 5 is a leaf. Return 5. - Node 2 result: 8 × 5 = 40. Return 40.
- Call
leafProduct(3). Node 3 is internal. Recurse left and right. - Call
leafProduct(6). Node 6 is a leaf. Return 6. - Call
leafProduct(9). Node 9 is a leaf. Return 9. - Node 3 result: 6 × 9 = 54. Return 54.
- Node 1 result: 40 × 54 = 2160. Return 2160.
The function never visits any node twice. Every leaf contributes its value exactly once.
Code in Python, Java, and C++
Python
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def leaf_product(root):
if root is None:
return 1
if root.left is None and root.right is None:
return root.data
return leaf_product(root.left) * leaf_product(root.right)
# Build the example tree
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(8)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(9)
print("Product of leaf nodes:", leaf_product(root))
# Output: 2160
Java
class Node {
int data;
Node left, right;
Node(int data) { this.data = data; }
}
class BinaryTree {
static long leafProduct(Node root) {
if (root == null) return 1;
if (root.left == null && root.right == null) return root.data;
return leafProduct(root.left) * leafProduct(root.right);
}
public static void main(String[] args) {
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(8);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.right.right = new Node(9);
System.out.println("Product of leaf nodes: " + leafProduct(root));
// Output: 2160
}
}
C++
#include <iostream>
using namespace std;
struct Node {
int data;
Node* left;
Node* right;
Node(int val) : data(val), left(nullptr), right(nullptr) {}
};
long long leafProduct(Node* root) {
if (!root) return 1;
if (!root->left && !root->right) return root->data;
return leafProduct(root->left) * leafProduct(root->right);
}
int main() {
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(8);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(9);
cout << "Product of leaf nodes: " << leafProduct(root) << endl;
// Output: 2160
return 0;
}
All three implementations return 2160 for the example tree. Note that Java and C++ use long / long long for the return type to handle larger products without overflow.
Time and Space Complexity
For a thorough reference on how these complexity classes arise across different algorithm patterns, see Space Complexity of Algorithms with Examples.
The complexity of the leaf-product traversal:
| Metric | Value | Reasoning |
|---|---|---|
| Time complexity | O(n) | Every node is visited exactly once |
| Space — balanced tree | O(log n) | Call stack depth equals tree height; height is log n for balanced trees |
| Space — skewed tree | O(n) | All nodes on one branch; call stack depth equals n |
Here, n is the total node count. The traversal does one unit of work per node: check null, check leaf, multiply. No node is revisited and no auxiliary data structure is created.
Edge Cases and Common Mistakes
Four situations that catch candidates off guard:
- Empty tree: the root is null. Return 1, not 0. Returning 0 means any subsequent multiply produces 0 regardless of actual leaf values.
- Single-node tree: the root is both the root and the only leaf. The null-check passes, the leaf-check triggers, and the function returns root.data directly. No multiplication needed.
- Skewed tree (all nodes on one side): the algorithm still works correctly. The recursion follows the chain down to the single leaf and returns its value. The null subtree at every other level returns 1, so nothing is zeroed out.
- Integer overflow: if leaf values are large or many leaves exist, the product can exceed a 32-bit integer range. Use
long longin C++ andlongin Java. Python’sintis arbitrary precision and will not overflow.
The most common wrong answer in coding rounds is returning 0 instead of 1 for null nodes. A candidate who writes if (root == null) return 0 will always get 0, no matter the tree. Test the base case mentally before submitting: trace through a two-leaf tree and confirm the result.
How This Pattern Generalises
The sum-of-digits traversal follows the same accumulate-and-recurse structure. Changing the null-return value and the combine operation produces a whole family of leaf-aggregate problems:
| Problem variant | Null returns | Leaf returns | Combine operation |
|---|---|---|---|
| Product of leaf nodes | 1 | node.data | left × right |
| Sum of leaf nodes | 0 | node.data | left + right |
| Count of leaf nodes | 0 | 1 | left + right |
| Maximum leaf node value | INT_MIN | node.data | max(left, right) |
| Leaf nodes at even depth | 1 | node.data if depth even, else 1 | left × right |
Recognising this family matters in interviews. If an interviewer follows up with “now find the sum of all leaf nodes,” the candidate who understands the three-part contract (what null returns, what a leaf returns, how the parent combines) adapts in under a minute.
According to GeeksforGeeks, leaf-aggregate problems are among the first tree problems a candidate should be able to write without reference. They test whether the recursion contract is understood, not whether advanced tree algorithms have been memorised.
The same three-part contract (null return, leaf return, combine operation) appears in JSON tree parsing, abstract syntax tree traversal in compilers, and decision tree inference in machine learning pipelines. TinkerLLM starts at ₹299 and covers how that pattern transfers from this kind of DFS problem to building working AI tools, where recursive structure is everywhere.
Primary sources
Frequently asked questions
What is a leaf node in a binary tree?
A leaf node is a node with no left child and no right child. It sits at the bottom of every root-to-leaf path and holds data but points to no further nodes.
Which traversal finds the product of all leaf nodes?
Any depth-first traversal works — preorder, inorder, or postorder. The standard recursive approach visits the current node, checks if it is a leaf, then recurses into left and right subtrees.
What is the time complexity of this algorithm?
O(n), where n is the number of nodes. Every node is visited exactly once regardless of tree shape — balanced or skewed.
What should the function return for an empty tree?
Return 1 (the multiplicative identity). Returning 0 would silently zero out any product the caller accumulates, giving a wrong answer for any non-empty subtree.
Can I solve this iteratively instead of recursively?
Yes. Push each node onto an explicit stack. When you pop a node with no children, multiply its value into a running product. Repeat until the stack is empty.
How do I prevent integer overflow when leaf values are large?
Use a 64-bit integer type: long long in C++, long in Java, or Python's arbitrary-precision int, which never overflows. For very large trees you can also compute the product modulo a prime.
A self-paced playground for building with LLMs.
TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.
Try TinkerLLM (₹299 launch)