Advertisement

Binary Tree Inorder Traversal - LeetCode 94 Solution

Binary Tree Inorder Traversal - Complete Solution Guide

Binary Tree Inorder Traversal is LeetCode problem 94, a Easy level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.

Problem Statement

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?

Detailed Explanation

This problem asks us to perform an 'inorder' traversal on a given binary tree and return a list of its node values in that specific order. 'Inorder' isn't just visiting nodes from left to right; it defines a precise sequence for each node: first, recursively traverse its *entire left subtree*, then visit the node itself (add its value to our result), and finally, recursively traverse its *entire right subtree*. This recursive definition applies consistently across every node in the tree. Consider the example `root = [1,null,2,3]`. For the root node `1`, we first process its left subtree (which is empty). Then, we add `1` to our result. Next, we move to its right subtree, rooted at `2`. Now, applying the inorder rule to `2`: its left child is `3`. So we process `3`'s left subtree (empty), then add `3` to the result, then process `3`'s right subtree (empty). After `3` is fully traversed, we return to `2`, add `2` to the result, and finally process `2`'s right subtree (empty). The final sequence is `[1,3,2]`. This specific traversal is particularly important because, for a Binary Search Tree, it conveniently yields the node values in sorted order.

Solution Approach

The provided solution implements an iterative Depth-First Search (DFS) for inorder traversal, cleverly circumventing explicit recursion by using an auxiliary stack. The core idea is to simulate the recursive call stack: we continuously descend down the left child path, pushing each visited node onto the stack. These stacked nodes represent ancestors whose left subtrees we're currently exploring, and whose values we haven't yet 'processed'. When we finally hit a `null` node (meaning we've gone as far left as possible in the current subtree), we know the leftmost node's left subtree is fully explored. It's then time to pop a node from the stack. This popped node is the 'current root' that we need to process (add its value to our result). Crucially, after processing this node, we immediately set `curr` to its *right* child. This ensures that the next iteration of the outer `while` loop will either continue descending left from this new `curr` (if it's not null), or, if it's null, we'll pop the next pending ancestor from the stack to process its value and then explore its right subtree. This loop continues until both `curr` is null and the stack is empty, meaning all nodes have been visited.

Step-by-Step Algorithm

  1. Step 1: Initialize an empty list `res` to store the inorder traversal result and an empty stack `stack`.
  2. Step 2: Initialize `curr` to the root node.
  3. Step 3: While `curr` is not null or the `stack` is not empty:
  4. Step 4: While `curr` is not null, push `curr` onto the `stack` and move `curr` to its left child (`curr.left`).
  5. Step 5: Pop the top node from the `stack` and assign it to `curr`.
  6. Step 6: Add `curr.val` to the `res` list.
  7. Step 7: Move `curr` to its right child (`curr.right`).
  8. Step 8: Return `res`.

Key Insights

  • An iterative Depth-First Search (DFS) for inorder traversal meticulously simulates the recursive call stack by using an explicit stack to store nodes whose left subtrees are yet to be fully explored. This allows us to defer processing a node's value until its entire left subtree has been visited.
  • The pattern of `while curr: stack.append(curr); curr = curr.left` is paramount. It ensures that we always push nodes onto the stack as we dive deep into the leftmost branch. The stack then acts as a 'breadcrumb trail' of parent nodes waiting for their left children to be fully processed.
  • The specific sequence of `curr = stack.pop(); res.append(curr.val); curr = curr.right` perfectly encapsulates the 'root-then-right' part of the inorder traversal. After popping and processing a node, we *must* immediately pivot to its right child to maintain the correct inorder sequence for that branch, repeating the 'descend-left' process from this new starting point.

Complexity Analysis

Time Complexity: O(n)

Space Complexity: O(n)

Topics

This problem involves: Stack, Tree, Depth-First Search, Binary Tree.

Companies

Asked at: Adobe, Amazon, Apple, Bloomberg, Meta, Microsoft, Uber.