GeeksforGeeks Medium

Bottom View of Binary Tree

Bottom View of Binary Tree is a GeeksforGeeks problem (Medium). Given the root of a binary tree, return the nodes you would see if you looked at the tree from below, listed from left to right.

  • Give every node a horizontal distance: the root is at 0, a left child is one less than its parent, and a right child is one more.
  • Nodes with the same horizontal distance form one vertical column. From below you see only the bottom-most node of each column.
  • If two nodes are equally low in the same column, the one that comes later in level-order traversal is the one you see.
  • Return one value per column, from the leftmost column to the rightmost.
Constraints
  • 1 <= number of nodes <= 10⁵
  • 1 <= node value <= 10⁵
treebfshash-table
Open on GeeksforGeeks ↗
02

Intuition

From below, each vertical column shows only its lowest node. The column is easy to carry down the tree: the root is 0, a left step subtracts 1 and a right step adds 1.

For "lowest", let the traversal order do the work. Breadth-first search visits the tree level by level, top to bottom and left to right, so the last node it visits in any column is the deepest one there, and on a tie the later one in level order. Overwriting the column on every visit therefore leaves exactly the bottom node, with no depth comparison at all.

How to spot this pattern

Any "view" of a tree (top, bottom, left, right) or vertical-order question starts by giving each node a coordinate, then keeping one node per coordinate. The traversal order decides which node wins: BFS naturally lets the lowest node write last. There is no bottom view of binary tree leetcode problem as such; the closest LeetCode relative is Vertical Order Traversal of a Binary Tree (987), which keeps every node in each column instead of one.

03

Approach

Try it first

Before reading on: label every node of a small tree with its column number. Which node in each column is lowest? Then decide which traversal visits that node last in its column without you checking depths.

1

Queue each node with its column

Start a queue with (root, 0). The column travels with the node, so it is computed once, when the child is enqueued.

2

Overwrite the column on every visit

Pop (node, col) and set seen[col] = node.data, with no check. BFS visits shallower levels first, so a later write in the same column always comes from a node at least as low.

3

Enqueue the children one column over

Push (node.left, col - 1) and (node.right, col + 1) for the children that exist. Only real nodes go in the queue.

4

Read the columns from left to right

When the queue is empty, sort the column keys and output their values. A sorted map (std::map, TreeMap) does this for you. Tracking the smallest and largest column instead lets you fill an array and skip the sort.

04

Bottom View of Binary Tree solution in Python | C++ | Java

▶1from collections import deque
▶2 
▶3class Solution:
▶4 def bottomView(self, root):
▶5 if not root:
▶6 return []
▶7 seen = {}
▶8 q = deque([(root, 0)])
▶9 while q:
▶10 node, col = q.popleft()
▶11 seen[col] = node.data
▶12 if node.left:
▶13 q.append((node.left, col - 1))
▶14 if node.right:
▶15 q.append((node.right, col + 1))
▶16 return [seen[c] for c in sorted(seen)]
col -2col -1col 0col 1col 22082253251014seen[col]queue = [(20, col 0)]
queue(20, 0)root starts in column 0
columns5one visible node each
Each shaded lane is one column: left children sit one lane left of their parent, right children one lane right. From below you see only the lowest node in each lane. BFS will visit the tree level by level, so the node that writes a lane last is its lowest.
col -2col -1col 0col 1col 22082253251014seen[col]20pop 20 → seen[0] = 20
node20column 0, depth 0
seen[0]20first write
queued8, 22children, one column over
Column 0 is empty, so 20 is the lowest node seen there so far. Its children join the queue one column to the left or right.
col -2col -1col 0col 1col 22082253251014seen[col]820pop 8 → seen[-1] = 8
node8column -1, depth 1
seen[-1]8first write
queued5, 3children, one column over
Column -1 is empty, so 8 is the lowest node seen there so far. Its children join the queue one column to the left or right.
col -2col -1col 0col 1col 22082253251014seen[col]82022pop 22 → seen[1] = 22
node22column 1, depth 1
seen[1]22first write
queued25children, one column over
Column 1 is empty, so 22 is the lowest node seen there so far. Its children join the queue one column to the left or right.
col -2col -1col 0col 1col 22082253251014seen[col]582022pop 5 → seen[-2] = 5
node5column -2, depth 2
seen[-2]5first write
queuednoneleaf
Column -2 is empty, so 5 is the lowest node seen there so far.
col -2col -1col 0col 1col 22082253251014seen[col]58322pop 3 → seen[0] = 3 (was 20)
node3column 0, depth 2
seen[0]3was 20
queued10, 14children, one column over
Column 0 already holds 20, but BFS reaches deeper levels later, so 3 is lower. Overwrite without comparing depths. Its children join the queue one column to the left or right.
col -2col -1col 0col 1col 22082253251014seen[col]5832225pop 25 → seen[2] = 25
node25column 2, depth 2
seen[2]25first write
queuednoneleaf
Column 2 is empty, so 25 is the lowest node seen there so far.
col -2col -1col 0col 1col 22082253251014seen[col]51032225pop 10 → seen[-1] = 10 (was 8)
node10column -1, depth 3
seen[-1]10was 8
queuednoneleaf
Column -1 already holds 8, but BFS reaches deeper levels later, so 10 is lower. Overwrite without comparing depths.
col -2col -1col 0col 1col 22082253251014seen[col]51031425pop 14 → seen[1] = 14 (was 22)
node14column 1, depth 3
seen[1]14was 22
queuednoneleaf
Column 1 already holds 22, but BFS reaches deeper levels later, so 14 is lower. Overwrite without comparing depths.
col -2col -1col 0col 1col 22082253251014bottom view51031425queue empty → return [5, 10, 3, 14, 25]
bottom view[5, 10, 3, 14, 25]columns -2 to 2
visits8each node once
Queue empty. The last write in each lane survived, and it is always that lane's lowest node (green). Reading the columns from smallest to largest gives the bottom view. The faded nodes were each overwritten by something lower.
col -2col -1col 0col 1col 22082253251014dfs, blind overwrite51032225DFS leaves 22 in col 1, not 14
DFS seen[1]22depth 1
correct14depth 3
Why BFS, not DFS. A preorder DFS finishes the whole left subtree first, so it writes 14 into column 1 and then reaches 22 on the right side and overwrites it, although 22 sits higher. A recursive version must carry the depth and only overwrite when the new node is at least as low.
05

Common pitfalls

Writing only when the column is empty

✗ Wrong
if col not in seen:
    seen[col] = node.data
✓ Right
seen[col] = node.data

Keeping the first node per column is the top-view rule. With BFS the first node in a column is the highest one, so this returns the top view.

Overwriting in a DFS without depths

✗ Wrong
def dfs(node, col):
    if node:
        seen[col] = node.data
        dfs(node.left, col - 1)
        dfs(node.right, col + 1)
✓ Right
def dfs(node, col, depth):
    if node:
        if col not in best or depth >= best[col][0]:
            best[col] = (depth, node.data)
        dfs(node.left, col - 1, depth + 1)
        dfs(node.right, col + 1, depth + 1)

DFS finishes the whole left subtree before the right one, so a shallow right-side node can be written after a deeper left-side node in the same column and wrongly replace it. With depths stored, the write happens only when the node is at least as low.

Returning the map in insertion order

✗ Wrong
return list(seen.values())
✓ Right
return [seen[c] for c in sorted(seen)]

A Python dict (or a C++ unordered_map, Java HashMap) keeps the order columns were first reached, which follows BFS, not left to right. The answer must be ordered by column.

06

Edge cases

Two nodes equally low in one column

A left child's right child and a right child's left child share both column and depth. The problem says the later one in level order is seen; BFS pushes left before right, so the unconditional overwrite already keeps that one.

07

Complexity

Time
O(n log n)
Space
O(n)
BFS touches each node once; the sorted map costs O(log n) per write. Tracking the minimum and maximum column and filling an array afterwards brings it to O(n). In the bottom view of binary tree Python code, sorted(seen) runs once over at most n column keys.
08

Top view, bottom view and vertical order

All three use the same column numbers. They differ only in which nodes of a column they keep.

ProblemKeeps per columnWrite rule in BFS
Top viewthe highest nodewrite only if the column is empty
Bottom viewthe lowest node (later one on a tie)overwrite every time
Vertical order traversalevery node, top to bottomappend to the column's list
09

Bottom View of Binary Tree FAQ

What is the bottom view of a binary tree?

The nodes seen when looking at the tree from underneath. Each vertical column (nodes with the same horizontal distance from the root) contributes its lowest node, and the columns are listed left to right. When two nodes are equally low in a column, the later one in level order is the one shown.

How do you find the bottom view of binary tree using recursion?

Pass the depth along with the column and store (depth, value) per column. Replace the stored entry only when the new node's depth is greater than or equal to the stored one. The >= matters: among equally deep nodes, preorder reaches them left to right, the same order as level order, so the later one wins as required. Without the depth check the recursion gives wrong answers.

Can you walk through a bottom view of binary tree example?

Take root 20 with children 8 and 22, where 8 has children 5 and 3, 3 has children 10 and 14, and 22 has a right child 25. The columns from left to right hold 5; 8 and 10; 20 and 3; 22 and 14; and 25. The lowest of each gives the bottom view 5 10 3 14 25.