Binary Trees · 9 of 35
Left View of a tree
Stand on the left side of a tree and write down the one person you can see on each floor.
- Simple way
- time O(n)
room O(w) - Clever way
- time O(n)
room O(h)
The problem, simply
You get a binary tree. Imagine you stand far away on its left side and look at it. On every floor (level) you can only see the first node, the one closest to you. Everyone else on that floor hides behind it.
Give back those visible nodes, from the top floor to the bottom floor.
The visible node on a floor is not always a left child. If the left side of the tree is short, a node from the right side can peek out on a lower floor.
A story to remember it
Picture it
From the left you see 1, 2, 4 and 7. Node 4 is a right child, and 7 sits deep in the right side, but nothing hides them on their floors.
- answer
- ignored
Examples
A right child peeks out
- In
[1, 2, 3, null, 4, 5, 6, null, null, null, null, 7]- Out
[1, 2, 4, 7]
Floor 2 holds 4, 5 and 6, and 4 is the leftmost. Floor 3 holds only 7, which lives under 6 on the right side.
A full tree
- In
[1, 2, 3, 4, 5, 6, 7]- Out
[1, 2, 4]
Here the left edge of the tree is exactly the left view.
Only right children
- In
[1, null, 2, null, 3]- Out
[1, 2, 3]
Each floor has one node, so you see all of them, even though none is a left child.
No tree
- In
[]- Out
[]
Nothing to see. Return an empty list.
Way 1: the simple way
Read the tree row by row with a waiting line (a queue), like level order. The first node you take out of each row is the one seen from the left.
- Put the root in the line.
- Read the line's size. That many nodes make up this row.
- Take them out one by one. Write down only the first one (
i == 0). Add every node's children to the back. - Repeat until the line is empty.
Row 2 is in the line: 4, 5, 6. The front one, 4, is the first of its row, so it goes in the answer.
- looking now
- done
- answer
- just added
import java.util.*;
class Solution {
public List<Integer> leftView(TreeNode root) {
List<Integer> out = new ArrayList<>();
if (root == null) return out;
Queue<TreeNode> line = new ArrayDeque<>();
line.add(root);
while (!line.isEmpty()) {
int size = line.size(); // nodes in this row
for (int i = 0; i < size; i++) {
TreeNode node = line.poll();
if (i == 0) out.add(node.val); // first one in the row
if (node.left != null) line.add(node.left);
if (node.right != null) line.add(node.right);
}
}
return out;
}
}How long it takes: every node joins and leaves the line once, O(n). Extra room: the line holds one whole row, O(w) where w is the widest row. That can be about n / 2.
Way 2: the clever way
Walk the tree going left first, and carry the floor number. Use the answer list itself as the memory of which floors are already taken: if the list has exactly floor names, nobody from this floor has been written yet.
- Visit a node with its floor number
d. - If
answer.size() == d, this is the first node we meet on floord. Add it. - Visit the left child with
d + 1, then the right child withd + 1.
Because left is always visited before right, the first node you meet on each floor is the leftmost one.
Go left first, write the first node of each floor
01 / 08
Visit 1 on floor 0. The answer has 0 names, so nobody from floor 0 is written yet. 1 is the first one we meet: write it down.
- answer size
- 1
- looking now
- seen
- answer
- path
- just added
import java.util.*;
class Solution {
public List<Integer> leftView(TreeNode root) {
List<Integer> out = new ArrayList<>();
see(root, 0, out);
return out;
}
private void see(TreeNode node, int floor, List<Integer> out) {
if (node == null) return;
if (out.size() == floor) out.add(node.val); // first one on this floor
see(node.left, floor + 1, out); // left first
see(node.right, floor + 1, out);
}
}How long it takes: each node once, O(n). Extra room: only the pile of waiting helpers, as tall as the tree, O(h). For a bushy tree that is much smaller than the widest row.
Watch out for
- Visiting right before left gives the right view, not the left view.
- Using a shared
maxLevelfield is fine, but reset it before every call, or a second call returns nothing. Usingout.size()avoids that bug. - An empty tree. Both ways return an empty list.
What interviewers ask next
- Right view: visit the right child first, or take the last node of each row in Way 1.
- Bottom view and top view: those look from below and above, so you need columns (left is -1, right is +1), not floors.
- Print the boundary of the tree: left edge, then all leaves, then the right edge upwards. The left view is a different thing from the left edge, so be careful.
- Can it be done with no recursion and no queue? You can simulate Way 2 with your own stack of (node, floor) pairs, pushing right before left.
Remember this
Grown-up words: floors are levels or depths, the waiting line is a queue for breadth first search, going left first with a floor number is a preorder depth first search, and the pile of waiting helpers is the call stack.