🧠
Better (DFS with Early Stopping)
💡 This approach improves on brute force by stopping recursion early when a leaf is found, avoiding unnecessary exploration of deeper paths.
Intuition
Use DFS to explore paths, but prune branches once a leaf is found and track the minimum depth found so far to avoid exploring longer paths.
Algorithm
- Initialize a variable to track minimum depth as infinity.
- Perform DFS traversal, passing current depth.
- When a leaf is found, update minimum depth if current depth is smaller.
- Prune recursion if current depth exceeds minimum depth found.
- Return the minimum depth after traversal.
💡 Pruning is the key optimization here, which can be subtle to implement correctly.
import math
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def minDepth(root):
min_depth = math.inf
def dfs(node, depth):
nonlocal min_depth
if not node:
return
if not node.left and not node.right:
min_depth = min(min_depth, depth)
return
if depth >= min_depth:
return
dfs(node.left, depth + 1)
dfs(node.right, depth + 1)
dfs(root, 1)
return 0 if min_depth == math.inf else min_depth
# Example usage:
if __name__ == '__main__':
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20, TreeNode(15), TreeNode(7))
print(minDepth(root)) # Output: 2
Line Notes
min_depth = math.infInitialize minimum depth to a very large number to track best found
def dfs(node, depth):Helper function to traverse tree with current depth parameter
if not node.left and not node.right:Leaf node found, update minimum depth if current path is shorter
if depth >= min_depth:Prune recursion if current path is already longer than best found
import java.util.*;
public class Solution {
public static class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
private int minDepthVal = Integer.MAX_VALUE;
public int minDepth(TreeNode root) {
if (root == null) return 0;
dfs(root, 1);
return minDepthVal;
}
private void dfs(TreeNode node, int depth) {
if (node == null) return;
if (node.left == null && node.right == null) {
minDepthVal = Math.min(minDepthVal, depth);
return;
}
if (depth >= minDepthVal) return;
dfs(node.left, depth + 1);
dfs(node.right, depth + 1);
}
public static void main(String[] args) {
Solution sol = new Solution();
TreeNode root = new TreeNode(3);
root.left = new TreeNode(9);
root.right = new TreeNode(20);
root.right.left = new TreeNode(15);
root.right.right = new TreeNode(7);
System.out.println(sol.minDepth(root)); // Output: 2
}
}
Line Notes
private int minDepthVal = Integer.MAX_VALUE;Track minimum depth found so far initialized to max
if (node.left == null && node.right == null)Leaf node base case to update minimum depth
if (depth >= minDepthVal) return;Prune deeper paths that cannot improve the result
dfs(node.left, depth + 1);Recurse left subtree with incremented depth
#include <iostream>
#include <algorithm>
#include <climits>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
int minDepthVal = INT_MAX;
void dfs(TreeNode* node, int depth) {
if (!node) return;
if (!node->left && !node->right) {
minDepthVal = min(minDepthVal, depth);
return;
}
if (depth >= minDepthVal) return;
dfs(node->left, depth + 1);
dfs(node->right, depth + 1);
}
int minDepth(TreeNode* root) {
if (!root) return 0;
minDepthVal = INT_MAX;
dfs(root, 1);
return minDepthVal;
}
int main() {
TreeNode* root = new TreeNode(3);
root->left = new TreeNode(9);
root->right = new TreeNode(20);
root->right->left = new TreeNode(15);
root->right->right = new TreeNode(7);
cout << minDepth(root) << endl; // Output: 2
return 0;
}
Line Notes
int minDepthVal = INT_MAX;Global variable to track minimum depth initialized to max
if (!node->left && !node->right)Leaf node found, update minimum depth
if (depth >= minDepthVal) return;Prune recursion if current depth is not better than best
dfs(node->left, depth + 1);Recurse left subtree with incremented depth
function TreeNode(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
function minDepth(root) {
let minDepthVal = Infinity;
function dfs(node, depth) {
if (!node) return;
if (!node.left && !node.right) {
minDepthVal = Math.min(minDepthVal, depth);
return;
}
if (depth >= minDepthVal) return;
dfs(node.left, depth + 1);
dfs(node.right, depth + 1);
}
dfs(root, 1);
return minDepthVal === Infinity ? 0 : minDepthVal;
}
// Example usage:
const root = new TreeNode(3, new TreeNode(9), new TreeNode(20, new TreeNode(15), new TreeNode(7)));
console.log(minDepth(root)); // Output: 2
Line Notes
let minDepthVal = Infinity;Initialize minimum depth to a large number to track best found
if (!node.left && !node.right)Leaf node base case to update minimum depth
if (depth >= minDepthVal) return;Prune recursion to avoid unnecessary deeper calls
dfs(node.left, depth + 1);Recurse left subtree with incremented depth
TimeO(n) in worst case, better on average due to pruning
SpaceO(h) recursion stack, where h is tree height
Pruning reduces unnecessary exploration, but worst case still visits all nodes.
💡 For a balanced tree with 20 nodes, pruning can save many calls, speeding up the search.
Interview Verdict: Accepted and more efficient than brute force in practice
This approach is a good improvement but still uses recursion and can be replaced by BFS for guaranteed shortest path.