Invert a Binary Tree

Asked in: Google, Amazon
Difficulty: Medium

Understanding the problem

Problem description: Invert a binary tree.

An inverted form of a Binary Tree is another Binary Tree with left and right children of all non-leaf nodes interchanged. You may also call it the mirror of the input tree.

NOTE: The tree is binary so there could be a maximum of two child nodes. This problem was originally inspired by this tweet by Max Howell .

Now, figure out that what does the interviewer mean when he says invert a binary tree, it would be helpful when you start looking at an example.

Example 1

Example 2

Explanation : You can observe that the root’s left pointer started pointing towards the right child and the right pointer towards the left child and a similar condition is noticed for all the sub root nodes.

The node structure for the BST passed to your function will be

class TreeNode
{
    int val
    TreeNode left
    TreeNode right
}

Recursive and iterative solutions

We will be discussing three approaches to solve this problem

  1. Recursive solution (similar to pre-order traversal) : Solve the problem by swapping the left and right child for the root of each subtree recursively.
  2. Using Iterative Preorder Traversal : We can convert the above recursive solution to iterative using stack.
  3. Using Level order traversal : iterative approach using queue

1. Recursive Solution

The key insight here is to realize that in order to invert a binary tree we only need to swap the children and recursively solve the two smaller sub-problems (same problem but for smaller input size) of left and right sub-tree. This looks similar to the idea of pre-order traversal.

The steps to be followed are  :

  • When the tree is empty return NULL . This is also our base case to stop recursive calls.
  • For every node encountered we swap its left and right child before recursively inverting its left and right subtree.
Pseudo Code
// Function to invert given binary Tree using preorder traversal
void invertBinaryTree(TreeNode root)
{
    // base case: if tree is empty
    if (root == Null)
        return
    // swap left subtree with right subtree
    swap(root.left, root.right)
    // invert left subtree
    invertBinaryTree(root.left)
    // invert right subtree
    invertBinaryTree(root.right)
}
Complexity Analysis

In the above approach, we are traversing each node of the tree only once. Time complexity : O(n)

Space Complexity of this algorithm is proportional to the maximum depth of recursion tree generated which is equal to the height of the tree (h).

Space complexity : O(h) for recursion call stack, where h is the height of the tree.

Critical ideas to think
  • Can we use idea similar to post-order traversal for solving this problem? or, can we use some other recursive idea for solution?
  • Why recursion help us to solve the tree problems easily? Explore the properties of Pre-order, In-Order and Post-Order traversal.
  • What is the space complexity in the worst and best-case scenario?

2. Using Iterative Preorder Traversal

Here, a Iterative Preorder Traversal is used to traverse the tree using a LIFO stack. To convert recursive procedures to iterative, we need an explicit stack during the implementation.

Solution Steps
  1. When the tree is empty return NULL.
  2. Create an empty stack S and push root node to stack.
  3. Do following while S is not empty :
  • Pop an item from stack S and swap the left child with right child
  • Push right child of popped item to the stack S.
  • Push left child of popped item to the stack S

Right child is pushed before left child to make sure that left subtree is processed first.

Pseudo Code
// Iterative Function to invert given binary Tree using stack
void invertBinaryTree(TreeNode root) 
{
    // base case: if tree is empty
    if (root is null) 
        return
    // create an empty stack and push root node
    stack S
    S.push(root)
    // iterate until the stack is not empty
    while (S is not empty)
    {
        // pop top node from stack
        TreeNode curr = S.top()
        S.pop()
        // swap left child with right child
        swap(curr.left, curr.right)
        // push right child of popped node to the stack
        if (curr.right)
            S.push(curr.right)
        // push left child of popped node to the stack
        if (curr.left)
            S.push(curr.left)
    }
}
Complexity Analysis

For each node in the tree, we are performing push() and pop() operation only once. Total no of stack operations = 2n (Think!)

Time complexity: O(n), where n is the total number of nodes.

Space Complexity: O(n) (Think!)

Critical Ideas to think
  • Visualize the stack operations via simple examples.
  • Explore the best and worst case scenario of space complexity.
  • Design iterative algorithms for in-order and post-order traversal (using stack).
  • Can we solve this problem using level-order traversal?

3. Using Level order traversal

We can solve this problem using Level Order Traversal. Here we the traverse the tree using a FIFO Queue.

In each iteration :

  • We are deleting one node from the queue : TreeNode curr = Q.dequeue()
  • Swapping the left and right child : swap(curr.left, curr.right)
  • Inserting left and right child to the queue
if (curr.left)             
   Q.enqueue(curr.left)       
if (curr.right)             
   Q.enqueue(curr.right)
Pseudo Code
// Iterative Function to invert given binary Tree using queue
void invertBinaryTree(TreeNode root) 
{
    // base case: if tree is empty
    if (root is NULL) 
        return
    // maintain a queue and push push root node
    queue Q
    Q.enqueue(root)
    // iterate untill queue is not empty
    while (Q is not empty) 
    {
        // pop top node from queue
        TreeNode curr = Q.dequeue()
        // swap left child with right child
        swap(curr.left, curr.right)
        // push left child of popped node to the queue
        if (curr.left)
            Q.enqueue(curr.left)
        // push right child of popped node to the queue
        if (curr.right)
            Q.enqueue(curr.right)
    }
}
Complexity Analysis

For each node in the tree, we are performing enqueue() and dequeue() operation only once. Total no of queue operations = 2n (Think!)

Time complexity: O(n), where n is the total number of nodes.

Space Complexity: O(n) (Think!)

Critical Ideas to think
  • Can you use a similar approach if the tree is generic?
  • Explore the best and worst case scenario of space complexity.
  • Can we write a recursive code for level order traversal? If yes then, compare its performance with Iterative Implementation (level order traversal using queue).

Comparison of different solutions

Suggested Problem to solve

  • Convert a given Binary tree to a tree that holds Logical AND property
  • Create a mirror tree from the given binary tree
  • Find mirror of a given node in a binary tree
  • Convert binary tree to threaded binary tree
  • Check if two binary trees are equal or not
  • Convert a given tree to its Sum Tree

If you have any more approaches or you find an error/bug in the above solutions, please comment down below.

Happy Coding! Enjoy Algorithms!

AfterAcademy Data Structure And Algorithms Online Course — Admissions Open