Binary Tree Preorder Traversal
LeetCode 144 | Difficulty: Easyβ
EasyProblem Descriptionβ
Given the root of a binary tree, return the preorder traversal of its nodes' values.
Example 1:
Input: root = [1,null,2,3]
Output: [1,2,3]
Explanation:

Example 2:
Input: root = [1,2,3,4,5,null,8,null,null,6,7,9]
Output: [1,2,4,5,6,7,3,8,9]
Explanation:

Example 3:
Input: root = []
Output: []
Example 4:
Input: root = [1]
Output: [1]
Constraints:
- The number of nodes in the tree is in the range `[0, 100]`.
- `-100 <= Node.val <= 100`
Follow up: Recursive solution is trivial, could you do it iteratively?
Topics: Stack, Tree, Depth-First Search, Binary Tree
Approachβ
Tree DFSβ
Traverse the tree recursively (or with a stack). At each node, decide: what information do I need from the left/right subtrees? Process: go left β go right β combine results. Consider preorder, inorder, or postorder traversal based on when you need to process the node.
Path problems, subtree properties, tree structure manipulation.
Stackβ
Use a stack (LIFO) to track elements that need future processing. Process elements when a "trigger" condition is met (e.g., finding a smaller/larger element). Monotonic stack maintains elements in sorted order for next greater/smaller element problems.
Matching brackets, next greater element, evaluating expressions, backtracking history.
Solutionsβ
Solution 1: C# (Best: 160 ms)β
| Metric | Value |
|---|---|
| Runtime | 160 ms |
| Memory | 38.7 MB |
| Date | 2021-12-08 |
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
public class Solution {
public IList<int> PreorderTraversal(TreeNode root) {
List<int> result = new List<int>();
TreeNode current = root, prev = null;
while (current != null)
{
if (current.left == null)
{
result.Add(current.val);
current = current.right;
}
else
{
// find predecessor
prev = current.left;
while (prev.right != null && prev.right != current)
{
prev = prev.right;
}
if (prev.right == null)
{
result.Add(current.val);
prev.right = current;
current = current.left;
}
else
{
prev.right = null;
current = current.right;
}
}
}
return result;
}
}
π 1 more C# submission(s)
Submission (2018-05-02) β 268 ms, N/Aβ
/**
* Definition for a binary tree node.
* public class TreeNode {
* public int val;
* public TreeNode left;
* public TreeNode right;
* public TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public IList<int> PreorderTraversal(TreeNode root) {
System.Collections.Generic.Stack<TreeNode> stack = new Stack<TreeNode>();
List<int> preorder = new List<int>();
if(root==null) return preorder;
stack.Push(root);
while (stack.Count != 0)
{
var popped = stack.Pop();
preorder.Add(popped.val);
if(popped.right!=null)
stack.Push(popped.right);
if(popped.left!=null)
stack.Push(popped.left);
}
return preorder;
}
}
Complexity Analysisβ
| Approach | Time | Space |
|---|---|---|
| Tree Traversal | $O(n)$ | $O(h)$ |
| Stack | $O(n)$ | $O(n)$ |
Interview Tipsβ
- Start by clarifying edge cases: empty input, single element, all duplicates.
- Consider: "What information do I need from each subtree?" β this defines your recursive return value.
- Think about what triggers a pop: is it finding a match, or finding a smaller/larger element?