Description
Given the root of a binary tree, return the inorder traversal of its nodes’ values.
Example 1:
Input: root = [1,null,2,3]
Output: [1,3,2]
Explanation:

Example 2:
Input: root = [1,2,3,4,5,null,8,null,null,6,7,9]
Output: [4,2,6,5,7,1,3,9,8]
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?
Approach - Recursion
class Solution {
List<Integer> ans = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
dfs(root);
return ans;
}
void dfs (TreeNode root) {
if (root == null) return;
dfs(root.left);
ans.add(root.val);
dfs(root.right);
}
}Approach 1: Recursive Traversal ( Time, Space)
Intuition
Traverse the binary tree following the in-order sequence: Left subtree Root node Right subtree. Recursively visit left nodes until hitting null, add the current node’s value to the result list, and then process the right child.
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
inorder(root, result);
return result;
}
private void inorder(TreeNode node, List<Integer> result) {
if (node == null) return;
inorder(node.left, result);
result.add(node.val);
inorder(node.right, result);
}
}
Complexity
- Time Complexity: — Every node in the binary tree is visited exactly once.
- Space Complexity: worst-case call stack depth for a skewed tree ( for a balanced tree).
Approach 2: Iterative Stack ( Time, Space)
Intuition
Simulate the recursion call stack using an explicit Stack:
- Push the current node and all of its left descendants onto the stack until reaching
null. - Pop the top node from the stack, visit it by appending its value to the result list.
- Move the pointer to its right child and repeat the process until both the current pointer and stack are empty.
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Deque<TreeNode> stack = new ArrayDeque<>(); // Standard modern Java Stack
TreeNode curr = root;
while (curr != null || !stack.isEmpty()) {
// Push all left children to stack
while (curr != null) {
stack.push(curr);
curr = curr.left;
}
// Process top element
curr = stack.pop();
result.add(curr.val);
// Move to right subtree
curr = curr.right;
}
return result;
}
}
Complexity
- Time Complexity: — Each node is pushed and popped from the stack at most once.
- Space Complexity: — Auxiliary space required for the explicit stack.
Approach 3: Morris Inorder Traversal (Optimal — Time, Space)
Intuition
Traverse without recursion or a stack by modifying tree pointers temporarily:
- If
curr.leftisnull, recordcurr.valand step right (curr = curr.right). - Otherwise, find the in-order predecessor (rightmost node in the left subtree):
- If
pred.rightisnull, create a temporary linkpred.right = currand move left (curr = curr.left). - If
pred.right == curr, restore the tree structure by settingpred.right = null, recordcurr.val, and move right (curr = curr.right).
- If
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
TreeNode curr = root;
while (curr != null) {
if (curr.left == null) {
result.add(curr.val);
curr = curr.right;
} else {
// Find in-order predecessor
TreeNode pred = curr.left;
while (pred.right != null && pred.right != curr) {
pred = pred.right;
}
if (pred.right == null) {
pred.right = curr; // Create temporary thread back to curr
curr = curr.left;
} else {
pred.right = null; // Remove thread and visit curr
result.add(curr.val);
curr = curr.right;
}
}
}
return result;
}
}
Complexity
- Time Complexity: — Traversing edges and restoring pointers takes at most steps in total.
- Space Complexity: auxiliary space — Tree structure modified temporarily without extra data structures.
Easy Memory Rule
“In-order pattern: Left Node Right. Push left nodes onto stack, pop & record, then step right!”
The Big Idea: “Temporary Threads”
In normal tree traversal, a stack or recursion is needed to remember how to get back up after visiting a left subtree.
Morris Traversal achieves auxiliary space by noticing that leaf nodes have unused null right pointers. It temporarily turns these null pointers into threads (links) pointing back to the current root node, and then destroys them when done.
The 3 Core Rules
For any node curr:
- If
currhas NO left child:- Visit
curr(addcurr.valto result). - Move right:
curr = curr.right.
- Visit
- If
currHAS a left child:- Find the in-order predecessor (the rightmost node of the left subtree).
- First time seeing this link (
pred.right == null):- Create thread:
pred.right = curr(saves our path back). - Move left:
curr = curr.left.
- Create thread:
- Second time seeing this link (
pred.right == curr):- Remove thread:
pred.right = null(restores original tree structure). - Visit
curr(addcurr.valto result). - Move right:
curr = curr.right.
- Remove thread:
Visual Step-by-Step
Consider this tree:
1
/ \
2 3
- Start at
curr = 1. Has left child2.- Predecessor of
1is2. - Set
2.right = 1(thread created). - Move to
curr = 2.
- Predecessor of
- At
curr = 2. Has NO left child.- **Visit
2**. - Move right following thread:
curr = 2.rightreturns to1!
- **Visit
- At
curr = 1. Has left child2.- Predecessor
2already points to1(2.right == 1). - Break thread:
2.right = null. - **Visit
1**. - Move right:
curr = 1.right3.
- Predecessor
- At
curr = 3. Has NO left child.- **Visit
3**. - Move right:
curr = null(Traversal complete).
Final Output:[2, 1, 3]
- **Visit
Why It’s Efficient
- Time Complexity: — Every edge in the tree is traversed at most twice (once to create the thread, once to remove it).
- Space Complexity: auxiliary space — No stack or recursion stack frame overhead; modifies pointers in-place temporarily.