Find Bottom Left Tree Value
Medium · Graphs · Explanation and code example
Morris Traversal
How it works
Morris traversal lets us traverse the tree without using extra space for a stack or recursion. We temporarily modify the tree by threading right pointers of predecessor nodes back to their successors, creating a way to return after visiting the left subtree. We track depth manually by counting steps down and back up, updating our result whenever we reach a new maximum depth.
Steps
- Initialize
resto the root's value,maxDepthto-1,curDepthto0, andcurto root. - While
curis notnull:- If
curhas no left child:- If
curDepth > maxDepth, updatemaxDepthandres. - Move to the right child and increment
curDepth.
- If
- Otherwise:
- Find the rightmost node in the left subtree (the predecessor), counting steps.
- If the predecessor's right pointer is
null, set it tocur, move left, and incrementcurDepth. - If it points back to
cur, restore it tonull, decrementcurDepthby the step count, and move right.
- If
- Return
res.
Complexity
- Time complexity:
O(n) - Space complexity:
O(1)extra space.
Things to watch for
Enqueueing Children in Wrong Order for BFS
The right-to-left BFS trick only works if right children are enqueued before left children. Reversing this order causes the last processed node to be the bottom-right instead of bottom-left.
Not Tracking Depth in DFS
When using DFS, updating the result without checking if the current depth exceeds the maximum seen depth causes incorrect values to be recorded. Always compare depths before updating the result.
Confusing Leftmost with First Encountered
The leftmost value at the deepest level is not necessarily the first node encountered during traversal. In DFS, left-first traversal combined with depth tracking ensures the leftmost node at maximum depth is correctly identified.
Python code example
from typing import Optional
# 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 findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
res, maxDepth, curDepth = root.val, -1, 0
cur = root
while cur:
if not cur.left:
if curDepth > maxDepth:
maxDepth, res = curDepth, cur.val
cur = cur.right
curDepth += 1
else:
prev = cur.left
steps = 1
while prev.right and prev.right != cur:
prev = prev.right
steps += 1
if not prev.right:
prev.right = cur
cur = cur.left
curDepth += 1
else:
prev.right = None
curDepth -= steps
cur = cur.right
return res
C++ code example
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
int res = root->val, maxDepth = -1, curDepth = 0;
TreeNode* cur = root;
while (cur) {
if (!cur->left) {
if (curDepth > maxDepth) {
maxDepth = curDepth;
res = cur->val;
}
cur = cur->right;
curDepth++;
} else {
TreeNode* prev = cur->left;
int steps = 1;
while (prev->right && prev->right != cur) {
prev = prev->right;
steps++;
}
if (!prev->right) {
prev->right = cur;
cur = cur->left;
curDepth++;
} else {
prev->right = nullptr;
curDepth -= steps;
cur = cur->right;
}
}
}
return res;
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.