LeetCode #94 Easy

Binary Tree Inorder Traversal

Binary Tree Inorder Traversal is LeetCode 94 (Easy). Given the root of a binary tree, return its node values in inorder: the left subtree, then the node, then the 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 real question is how to do it without recursion.

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

Recursion writes a binary tree inorder traversal in three lines but hides its bookkeeping in the call stack. An iterative inorder traversal keeps that bookkeeping in a stack of its own.

The rule behind it: a node can be output only after its whole left subtree. So every node passed on the way left has to wait, and the one passed last is the first one ready. Last in, first out is exactly what a stack gives, and it only ever holds one root-to-leaf path, so it needs O(h) space.

How to spot this pattern

Inorder is the order to reach for on a binary search tree: left, node, right visits the values in ascending order. Validate BST, Kth Smallest Element in a BST, Recover BST and BST Iterator are all this traversal with a check in place of the append. The stack loop is also exactly how a BST iterator pauses between calls to next().

03

Approach

Try it first

Before reading on: in the tree [1,2,3,4,5], which nodes are still waiting at the moment 4 is output, and in what order must they come out? Which data structure hands them back in that order?

1

Walk left, pushing every node

From node, push it and move to node.left, until node is empty. Each pushed node is waiting for its left subtree to finish first.

2

Pop and record

When node is empty, pop the top of the stack and append its value. Everything to its left is already in the answer, because its left subtree was finished before it reached the top again.

3

Move to the right child

Set node = node.right and go back to the first step. The right subtree comes after the node in inorder and is handled like a fresh tree. If it is empty, the next pop returns the nearest ancestor still waiting.

4

Stop when both are empty

The loop runs while node or the stack is non-empty. Each node is pushed once and popped once, so the walk is O(n) time, and the stack holds at most one root-to-node path, O(h) space.

04

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

▶1class Solution:
▶2 def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
▶3 result, stack = [], []
▶4 node = root
▶5 while node or stack:
▶6 while node:
▶7 stack.append(node)
▶8 node = node.left
▶9 node = stack.pop()
▶10 result.append(node.val)
▶11 node = node.right
▶12 return result
on stackin answer123stackemptyansweremptynode = root (1)
node1start at the root
stack[ ]
Start at the root. Inorder puts a node after its whole left subtree, so the root cannot be output yet. The walk heads left first, and the stack remembers every node it passes.
on stackin answer123stack1topansweremptypush 1, no left child
push1waits for its left side
stack[1]top on the right
nodeNonenode.left
Push 1. It has no left child, so node becomes empty and the inner loop stops: nothing is left to the left of 1.
on stackin answer123stackemptyanswer1pop 1 → answer, go right to 2
pop1left side finished
result[1]1 of 3
node2node.right
Everything left of 1 is already in the answer, so it is next. Its right subtree comes after it, so node moves to 2 and the walk-left loop starts again from there.
on stackin answer123stack2topanswer1push 2, go left to 3
push2waits for its left side
stack[2]top on the right
node3node.left
2 has a left child, so its left subtree must be output first. Push 2 to come back to it later, and move left to 3.
on stackin answer123stack23topanswer1push 3, no left child
push3waits for its left side
stack[2, 3]top on the right
nodeNonenode.left
Push 3. It has no left child, so node becomes empty and the inner loop stops: nothing is left to the left of 3.
on stackin answer123stack2topanswer13pop 3 → answer, no right child
pop3left side finished
result[1, 3]2 of 3
nodeNonenode.right
Everything left of 3 is already in the answer, so it is next. It has no right child, so the next pop returns 2, the nearest ancestor still waiting.
on stackin answer123stackemptyanswer132pop 2 → answer, no right child
pop2left side finished
result[1, 3, 2]3 of 3
nodeNonenode.right
Everything left of 2 is already in the answer, so it is next. It has no right child, so nothing is left to visit.
on stackin answer123stackemptyanswer132stack empty → return [1, 3, 2]
result[1, 3, 2]left, node, right
work3 pushes, 3 popsO(n)
Done. node is empty and so is the stack. Every node was pushed once and popped once, and each was popped only after its entire left subtree, which is exactly inorder.
05

Recursive inorder traversal

dfs(node) returns at once on an empty node; otherwise it visits the left subtree, appends node.val, then visits the right subtree. The call stack does the job of the explicit stack.

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

Common pitfalls

Recording a node when it is pushed

✗ Wrong
while node:
    result.append(node.val)
    stack.append(node)
    node = node.left
✓ Right
node = stack.pop()
result.append(node.val)

Appending on the way down outputs each node before its left subtree, which is preorder. For [1,2,3] it gives [1, 2, 3] instead of [2, 1, 3].

Looping only while the stack is non-empty

✗ Wrong
while stack:
✓ Right
while node or stack:

The stack is empty at the start and again right after the root is popped, yet node still has work: first the root itself, later the root's right subtree. while stack stops at those moments and returns too little.

Building the answer by list concatenation

✗ Wrong
return dfs(node.left) + [node.val] + dfs(node.right)
✓ Right
result.append(node.val)  # one shared list

In a binary tree inorder traversal Python solution written this way, each + copies the lists built so far. On a chain-shaped tree that is O(n²) work; appending to one list is O(1) per node.

07

Edge cases

Empty tree

node starts as None and the stack is empty, so the loop never runs and the answer is [].

A left-skewed chain

Every node is pushed before the first pop, so the stack grows to n: the O(h) space bound is O(n) in the worst case.

08

Complexity

Time
O(n)
Space
O(h)
Each node is pushed and popped once. The stack holds one path: O(log n) for a balanced tree, O(n) for a chain.
09

Binary Tree Inorder Traversal FAQ

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

Yes, with Morris traversal. Before going left, it links the rightmost node of the left subtree back to the current node, follows that link to come back up, and then removes it. Time stays O(n) and the tree is restored by the end.