🧠
Brute Force (DFS with Tracking Depth and Leftmost Node)
💡 This approach uses a simple depth-first search to explore all nodes, tracking the deepest level and the leftmost node found at that level. It is intuitive and helps understand the problem deeply before optimizing.
Intuition
Traverse the tree recursively, keeping track of the current depth. Whenever you reach a new maximum depth, record the node's value as the leftmost node at that depth.
Algorithm
- Initialize variables to track maximum depth and leftmost value.
- Perform DFS starting from root at depth 0.
- At each node, if current depth > max depth, update max depth and leftmost value.
- Recursively visit left child first, then right child to ensure leftmost priority.
💡 The key is visiting left child before right to ensure the first node at a new depth is the leftmost.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
self.max_depth = -1
self.leftmost_value = 0
def dfs(node, depth):
if not node:
return
if depth > self.max_depth:
self.max_depth = depth
self.leftmost_value = node.val
dfs(node.left, depth + 1)
dfs(node.right, depth + 1)
dfs(root, 0)
return self.leftmost_value
# Driver code to test
if __name__ == '__main__':
root = TreeNode(1, TreeNode(2, TreeNode(4)), TreeNode(3, TreeNode(5, TreeNode(7)), TreeNode(6)))
sol = Solution()
print(sol.findBottomLeftValue(root)) # Expected output: 7
Line Notes
self.max_depth = -1Initialize max_depth to -1 to ensure root at depth 0 updates it
self.leftmost_value = 0Placeholder for leftmost value, updated when deeper node found
if depth > self.max_depth:Check if current node is deeper than any previously visited
dfs(node.left, depth + 1)Visit left child first to prioritize leftmost nodes
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
private int maxDepth = -1;
private int leftmostValue = 0;
public int findBottomLeftValue(TreeNode root) {
dfs(root, 0);
return leftmostValue;
}
private void dfs(TreeNode node, int depth) {
if (node == null) return;
if (depth > maxDepth) {
maxDepth = depth;
leftmostValue = node.val;
}
dfs(node.left, depth + 1);
dfs(node.right, depth + 1);
}
// Driver code
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.right.left = new TreeNode(5);
root.right.right = new TreeNode(6);
root.right.left.left = new TreeNode(7);
Solution sol = new Solution();
System.out.println(sol.findBottomLeftValue(root)); // Expected: 7
}
}
Line Notes
private int maxDepth = -1;Initialize maxDepth to -1 so root at depth 0 updates it
if (depth > maxDepth)Update leftmostValue only when a deeper node is found
dfs(node.left, depth + 1);Traverse left subtree first to ensure leftmost priority
public static void main(String[] args)Driver code to test the solution with example tree
#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
int maxDepth = -1;
int leftmostValue = 0;
void dfs(TreeNode* node, int depth) {
if (!node) return;
if (depth > maxDepth) {
maxDepth = depth;
leftmostValue = node->val;
}
dfs(node->left, depth + 1);
dfs(node->right, depth + 1);
}
public:
int findBottomLeftValue(TreeNode* root) {
dfs(root, 0);
return leftmostValue;
}
};
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->right->left = new TreeNode(5);
root->right->right = new TreeNode(6);
root->right->left->left = new TreeNode(7);
Solution sol;
cout << sol.findBottomLeftValue(root) << endl; // Expected: 7
return 0;
}
Line Notes
int maxDepth = -1;Start maxDepth at -1 so root at depth 0 updates it
if (depth > maxDepth)Update leftmostValue only when a deeper node is found
dfs(node->left, depth + 1);Visit left child first to prioritize leftmost nodes
int main()Driver code to build example tree and test solution
class TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
constructor() {
this.maxDepth = -1;
this.leftmostValue = 0;
}
findBottomLeftValue(root) {
const dfs = (node, depth) => {
if (!node) return;
if (depth > this.maxDepth) {
this.maxDepth = depth;
this.leftmostValue = node.val;
}
dfs(node.left, depth + 1);
dfs(node.right, depth + 1);
};
dfs(root, 0);
return this.leftmostValue;
}
}
// Driver code
const root = new TreeNode(1,
new TreeNode(2, new TreeNode(4)),
new TreeNode(3, new TreeNode(5, new TreeNode(7)), new TreeNode(6))
);
const sol = new Solution();
console.log(sol.findBottomLeftValue(root)); // Expected output: 7
Line Notes
this.maxDepth = -1;Initialize maxDepth so root at depth 0 updates it
if (depth > this.maxDepth)Update leftmostValue only when a deeper node is found
dfs(node.left, depth + 1);Traverse left subtree first to ensure leftmost priority
console.log(sol.findBottomLeftValue(root));Print result to verify correctness
We visit each node once (n nodes). The recursion stack can go as deep as the tree height h.
💡 For a tree with 100,000 nodes, this means 100,000 visits; stack depth depends on tree shape.
Interview Verdict: Accepted
This approach is efficient enough for large trees and easy to implement, making it a solid baseline.