LeetCode #144 Easy

Binary Tree Preorder Traversal

Binary Tree Preorder Traversal is LeetCode 144 (Easy). Given the root of a binary tree, return its node values in preorder: the node, then its left subtree, then its right subtree.

  • The tree can be empty; then the answer is [].
  • Follow-up: the recursive solution is trivial, so do it iteratively.

With at most 100 nodes any O(n) walk is fast; the point is to replace the recursion with a stack you manage yourself.

Constraints
  • The number of nodes in the tree is in the range [0, 100].
  • -100 <= Node.val <= 100
binary treedfsrecursion
Open on LeetCode ↗
02

Intuition

In a binary tree preorder traversal a node is output as soon as it is reached, before anything below it. So an iterative preorder traversal only has to track which subtrees are still waiting, and a stack does that: pop a node, record it, push its children.

The one twist is the order. A stack returns the last item pushed, so the children go in right first, left second. The left subtree is then finished before the right one starts, giving node, left, right.

How to spot this pattern

Preorder is the order to use when a node must be handled before its children: copying or serialising a tree, printing a folder hierarchy, or passing a value down from parent to child. Serialize and Deserialize Binary Tree, Flatten Binary Tree to Linked List and Construct Binary Tree from Preorder and Inorder Traversal all rely on the root coming first.

03

Approach

Try it first

Before reading on: for the tree [1,2,3,4,5], the answer is [1, 2, 4, 5, 3]. After you output 1, both 2 and 3 are waiting. If you keep them on a stack, in which order must you push them so that 2 comes out first?

1

Return early for an empty tree

If root is empty, return []. Otherwise start the stack with the root. Each node on the stack stands for a whole subtree still to visit, so the stack never holds an empty node.

2

Pop and record

Pop the top node and append its value straight away. A node comes before its children in preorder, so there is nothing to wait for: the moment it leaves the stack is its place in the answer.

3

Push right, then left

Push the node's children, skipping empty ones:

  • the right child first;
  • the left child second, so it is on top.

The stack returns the last item pushed, so the left subtree is finished before the right child is popped.

4

Stop when the stack is empty

An empty stack means no subtree is left. Each node is pushed once and popped once, so the walk is O(n) time; the stack holds O(h) nodes for a typical tree and never more than n.

04

Binary Tree Preorder Traversal solution in Python | C++ | Java

▶1class Solution:
▶2 def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
▶3 if not root:
▶4 return []
▶5 result, stack = [], [root]
▶6 while stack:
▶7 node = stack.pop()
▶8 result.append(node.val)
▶9 if node.right:
▶10 stack.append(node.right)
▶11 if node.left:
▶12 stack.append(node.left)
▶13 return result
on stackin answer123stack1topansweremptypush the root (1)
stack[1]subtrees still to visit
result[ ]
Start with the root on the stack. Each node on the stack stands for a whole subtree that still has to be visited, and the top is always the one preorder needs next.
on stackin answer123stackemptyanswer1pop 1 → answer
pop1node comes before its children
result[1]1 of 3
stack[]top on the right
Pop 1 and record it right away: in preorder a node comes before everything below it. Its children are pushed next.
on stackin answer123stack2topanswer1push right child 2 first
push2right child of 1
stack[2]top on the right
Push the right child 2 first. A stack gives back the last thing pushed, so pushing right before left makes the right subtree wait until the whole left subtree is done.
on stackin answer123stackemptyanswer12pop 2 → answer
pop2node comes before its children
result[1, 2]2 of 3
stack[]top on the right
Pop 2 and record it right away: in preorder a node comes before everything below it. Its children are pushed next.
on stackin answer123stack3topanswer12push left child 3 on top
push3left child of 2
stack[3]top on the right
Push the left child 3 last, so it sits on top and is popped next. That is preorder's node, then left, then right.
on stackin answer123stackemptyanswer123pop 3 → answer (leaf, nothing to push)
pop3node comes before its children
result[1, 2, 3]3 of 3
stack[]top on the right
Pop 3 and record it. It is a leaf, so nothing is pushed, and the stack is now empty.
on stackin answer123stackemptyanswer123stack empty → return [1, 2, 3]
result[1, 2, 3]node, left, right
work3 pushes, 3 popsO(n)
Done. The stack is empty, so no subtree is left. Every node was pushed once and popped once, and each was recorded the moment it was popped, before any of its children.
05

Recursive preorder traversal

dfs(node) returns at once on an empty node; otherwise it appends node.val, then visits the left subtree, then the right subtree. The call stack keeps track of where to return.

▶1class Solution:
▶2 def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
▶3 result = []
▶4 
▶5 def dfs(node):
▶6 if not node:
▶7 return
▶8 result.append(node.val)
▶9 dfs(node.left)
▶10 dfs(node.right)
▶11 
▶12 dfs(root)
▶13 return result
06

Common pitfalls

Pushing the left child first

✗ Wrong
if node.left:
    stack.append(node.left)
if node.right:
    stack.append(node.right)
✓ Right
if node.right:
    stack.append(node.right)
if node.left:
    stack.append(node.left)

The stack returns the last child pushed, so the right subtree would be visited before the left. For [1,2,3] the answer comes out [1, 3, 2] instead of [1, 2, 3].

Pushing empty children

✗ Wrong
stack.append(node.right)
stack.append(node.left)
✓ Right
if node.right:
    stack.append(node.right)

In Python a later pop returns None and node.val crashes. In a binary tree preorder traversal Java version, ArrayDeque.push(null) throws a NullPointerException at once. Check each child before pushing it.

Recording the node after its children

✗ Wrong
def dfs(node):
    if not node:
        return
    dfs(node.left)
    dfs(node.right)
    result.append(node.val)
✓ Right
def dfs(node):
    if not node:
        return
    result.append(node.val)
    dfs(node.left)
    dfs(node.right)

Where the append sits is the only difference between the depth-first orders. After both calls it is postorder; for [1,2,3] that gives [2, 3, 1].

07

Complexity

Time
O(n)
Space
O(h)
Each node is pushed and popped once. The stack holds roughly one path plus the right siblings waiting beside it; at most n nodes.
08

Binary Tree Preorder Traversal FAQ

Can LeetCode 144 be solved in O(1) extra space?

Yes, with Morris traversal. It records a node, then links the rightmost node of its left subtree back to it, so the walk can climb back up without a stack. The links are removed on the way back. Time stays O(n).