Open In App

Minimum nodes to be removed to make a Binary tree complete

Last Updated : 27 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a binary tree with positive values of nodes, find the minimum number of nodes that need to be removed to transform it into a complete binary tree. Return 0 if the given tree is already complete.

Note: A complete binary tree is a special type of binary tree where all the levels of the tree are filled completely except possibly the lowest level nodes which are filled from as left as possible.

Examples: 

Input:                                           

Input example tree 1

Output:  1
Explanation: If we remove node 6, it will transform into the complete binary tree. Note that we could also remove all the nodes of the last level which will also convert it to complete but it will not be the minimum.

Input:                                            

Input example tree 2

Output: 3
Explanation: Nodes 6, 7, and 8 are to be removed.

Approach: To solve the problem using BFS (Breadth First Search) follow the below idea:

Using BFS (Breadth First Search): BFS is the most intuitive algorithm here. We will traverse through each level of the given binary tree and when we find the first null node after that all other nodes have to be removed (if present) to convert it to a complete binary tree, So we will count those nodes and return it as our answer. 

Steps that were to follow the above approach:

  • Start the BFS traversal with the root node.
  • To keep track of the null node create a boolean “nullFound” with starting value of false.
  • Now when the first null node is found make “nullFound” true.
  • As soon as “nullFound” becomes true, count all preceding nodes of the same level as well as of below levels.

Below is the code to implement the above steps:

C++




// C++ code for the above approach
#include <bits/stdc++.h>
 
using namespace std;
 
// Definition for a binary tree node
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x)
        : val(x), left(NULL), right(NULL)
    {
    }
};
 
int minNodesToBeRemoved_bfs(TreeNode* root)
{
    if (!root)
        return 0;
 
    // Initialize empty queue
    queue<TreeNode*> q;
 
    // push root and start bfs
    q.push(root);
 
    // Variable to store if null has
    // been found or not
    bool nullFound = false;
    int ans = 0;
 
    while (q.size()) {
        auto front = q.front();
        q.pop();
 
        if (front->left) {
            q.push(front->left);
 
            // If node is present and null
            // has been found increase the
            // answer by 1
            if (nullFound)
                ans++;
        }
 
        // If node is null make
        // nullFound true
        else
            nullFound = true;
 
        // Do the same for right node
        if (front->right) {
            q.push(front->right);
            if (nullFound)
                ans++;
        }
        else
            nullFound = true;
    }
 
    // Return the answer
    return ans;
}
 
// Driver's code
int main()
{
 
    /*
     *
     *             1
     *           /   \
     *          2     3
     *         / \     \
     *        4   5     6
     *           / \
     *          7   8
     *
     *        Output: 3
     */
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);
    root->right->right = new TreeNode(6);
    root->left->right->left = new TreeNode(7);
    root->left->right->right = new TreeNode(8);
 
    cout << "Minimum number of nodes to be removed to make "
            "the tree complete is: ";
 
    // Function Call
    cout << minNodesToBeRemoved_bfs(root) << endl;
 
    return 0;
}


Python3




# Python code for the above approach
from queue import Queue
 
# Definition for a binary tree node
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
 
def minNodesToBeRemoved_bfs(root: TreeNode) -> int:
    if not root:
        return 0
 
    # Initialize empty queue
    q = Queue()
 
    # push root and start bfs
    q.put(root)
 
    # Variable to store if null has
    # been found or not
    nullFound = False
    ans = 0
 
    while not q.empty():
        front = q.get()
 
        if front.left:
            q.put(front.left)
 
            # If node is present and null
            # has been found increase the
            # answer by 1
            if nullFound:
                ans += 1
 
        # If node is null make
        # nullFound true
        else:
            nullFound = True
 
        # Do the same for right node
        if front.right:
            q.put(front.right)
            if nullFound:
                ans += 1
        else:
            nullFound = True
 
    # Return the answer
    return ans
 
# Driver's code
if __name__ == '__main__':
 
    """
    *
    *             1
    *           /   \
    *          2     3
    *         / \     \
    *        4   5     6
    *           / \
    *          7   8
    *
    *        Output: 3
    """
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(3)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(5)
    root.right.right = TreeNode(6)
    root.left.right.left = TreeNode(7)
    root.left.right.right = TreeNode(8)
 
    print("Minimum number of nodes to be removed to make "
          "the tree complete is: ", minNodesToBeRemoved_bfs(root))


C#




// C# code for the above approach
 
using System;
using System.Collections.Generic;
 
// Definition for a binary tree node
public class TreeNode
{
    public int val;
    public TreeNode left;
    public TreeNode right;
 
    public TreeNode(int x)
    {
        val = x;
        left = null;
        right = null;
    }
}
 
public class Solution
{
    public static int minNodesToBeRemoved_bfs(TreeNode root)
    {
        if (root == null)
            return 0;
 
        // Initialize empty queue
        Queue<TreeNode> q = new Queue<TreeNode>();
 
        // push root and start bfs
        q.Enqueue(root);
 
        // Variable to store if null has
        // been found or not
        bool nullFound = false;
        int ans = 0;
 
        while (q.Count > 0)
        {
            var front = q.Dequeue();
 
            if (front.left != null)
            {
                q.Enqueue(front.left);
 
                // If node is present and null
                // has been found increase the
                // answer by 1
                if (nullFound)
                    ans++;
            }
 
            // If node is null make
            // nullFound true
            else
                nullFound = true;
 
            // Do the same for right node
            if (front.right != null)
            {
                q.Enqueue(front.right);
                if (nullFound)
                    ans++;
            }
            else
                nullFound = true;
        }
 
        // Return the answer
        return ans;
    }
 
    // Driver's code
    static void Main()
    {
        /*
         *
         *             1
         *           /   \
         *          2     3
         *         / \     \
         *        4   5     6
         *           / \
         *          7   8
         *
         *        Output: 3
         */
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);
        root.right.right = new TreeNode(6);
        root.left.right.left = new TreeNode(7);
        root.left.right.right = new TreeNode(8);
 
        Console.Write("Minimum number of nodes to be removed to make " +
                        "the tree complete is: ");
 
        // Function Call
        Console.WriteLine(minNodesToBeRemoved_bfs(root));
    }
}


Java




// Java code to implement the above approach
import java.util.LinkedList;
import java.util.Queue;
 
// Definition for a binary tree node
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
 
    TreeNode(int x)
    {
        val = x;
        left = null;
        right = null;
    }
}
 
public class GFG {
    public static int minNodesToBeRemoved_bfs(TreeNode root)
    {
        if (root == null)
            return 0;
 
        // initialize empty queue
        Queue<TreeNode> q = new LinkedList<>();
        // push root and start bfs
        q.offer(root);
        // variable to store if null has been found or not
        boolean nullFound = false;
        int ans = 0;
 
        while (!q.isEmpty()) {
            TreeNode front = q.poll();
 
            if (front.left != null) {
                q.offer(front.left);
                // if node is present and null has been
                // found increase the answer by 1
                if (nullFound)
                    ans++;
            }
            else
                // if node is null make nullFound true
                nullFound = true;
 
            // do the same for right node
            if (front.right != null) {
                q.offer(front.right);
                if (nullFound)
                    ans++;
            }
            else
                nullFound = true;
        }
        // return the answer
        return ans;
    }
 
    // Driver's code
    public static void main(String[] args)
    {
        /*
         *
         *             1
         *           /   \
         *          2     3
         *         / \     \
         *        4   5     6
         *           / \
         *          7   8
         *
         *        Output: 3
         */
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);
        root.right.right = new TreeNode(6);
        root.left.right.left = new TreeNode(7);
        root.left.right.right = new TreeNode(8);
 
        System.out.print(
            "Minimum number of nodes to be removed to make the tree complete is: ");
        System.out.println(minNodesToBeRemoved_bfs(root));
    }
}


Javascript




// Javascript code for the above approach
 
// Definition for a binary tree node
class TreeNode {
    constructor(val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}
 
function minNodesToBeRemoved_bfs(root) {
    if (!root)
        return 0;
 
    // Initialize empty queue
    const q = [];
 
    // push root and start bfs
    q.push(root);
 
    // Variable to store if null has
    // been found or not
    let nullFound = false;
    let ans = 0;
 
    while (q.length) {
        const front = q.shift();
 
        if (front.left) {
            q.push(front.left);
 
            // If node is present and null
            // has been found increase the
            // answer by 1
            if (nullFound)
                ans++;
        }
 
        // If node is null make
        // nullFound true
        else
            nullFound = true;
 
        // Do the same for right node
        if (front.right) {
            q.push(front.right);
            if (nullFound)
                ans++;
        }
        else
            nullFound = true;
    }
 
    // Return the answer
    return ans;
}
 
// Driver's code
(() => {
 
    /*
     *
     *             1
     *           /   \
     *          2     3
     *         / \     \
     *        4   5     6
     *           / \
     *          7   8
     *
     *        Output: 3
     */
    const root = new TreeNode(1);
    root.left = new TreeNode(2);
    root.right = new TreeNode(3);
    root.left.left = new TreeNode(4);
    root.left.right = new TreeNode(5);
    root.right.right = new TreeNode(6);
    root.left.right.left = new TreeNode(7);
    root.left.right.right = new TreeNode(8);
 
    console.log("Minimum number of nodes to be removed to make the tree complete is: ");
 
    // Function Call
    console.log(minNodesToBeRemoved_bfs(root));
 
})();


Output

Minimum number of nodes to be removed to make the tree complete is: 3

Time Complexity: O(n), (n is the number of nodes) because we are traversing through all the nodes.
Auxiliary Space: O(n), (n is the number of nodes) queue is used to contain all the nodes.

Approach:  

Using DFS (Depth First Search): Using DFS for this problem is a little bit tricky. We can not directly check, at which level the first null node is found as in the above approach. So we will create an array and store the elements of the given tree (level-wise) in it, at a specific index such that if the tree was complete all the nodes would be filled in the array before a null appears. After the first null node is found the count of all the preceding nodes is our answer. 

Steps that were to follow the above approach:

  • Find the height of the binary tree ‘h’ using DFS.
  • For a complete tree, the maximum nodes can be (2h – 1).
  • Create an array of size (2h – 1) to store nodes level-wise.
  • Now start the DFS with root and keep filling the array.
  • For all, DFS calls if the root is at index “idx” put the left node at index 2*idx+1 and the right node at 2*idx+2.
  • Now traverse through the array and keep a track of the first null node.
  • If there are any other nodes after the first null node count them and return.

Illustration of the above steps:

Given Tree:

                       1
                     /   \ 
                  2      3
                 / \      \ 
               4   5      6
                   / \
                7   8 

  • Height of the tree: 4, Maximum possible Nodes : 24 – 1 = 15.
  • Initial Array:  |-1| |-1| |-1| |-1| ….. 15 blocks.
  • Array after DFS traversal: |1| |2| |3| |4| |5| |-1| |6| |-1| |-1| |7| |8| |-1| |-1| |-1| |-1|.
  • The first null node found at index 5 after that nodes 6, 7 and 8 are present. So the answer is 3.

Below is the code to implement the above steps:

C++




// C++ code for the above approach
#include <bits/stdc++.h>
 
using namespace std;
 
// Definition for a binary tree node
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x)
        : val(x), left(NULL), right(NULL)
    {
    }
};
 
// Function to calculate the
// height of the tree
int height(TreeNode* root)
{
    if (!root)
        return 0;
    return 1 + max(height(root->left), height(root->right));
}
 
// dfs traversal to fill the array
void dfs(TreeNode* root, int index, vector<int>& arr)
{
    if (!root)
        return;
 
    arr[index] = root->val;
    dfs(root->left, 2 * index + 1, arr);
    dfs(root->right, 2 * index + 2, arr);
}
 
int minNodesToBeRemoved_dfs(TreeNode* root)
{
    int h = height(root);
 
    // Find the size of the array
    int maxNodes = (1 << h) - 1;
 
    // Make an array to store the
    // nodes level wise
    vector<int> arr(maxNodes, -1);
 
    // dfs call
    dfs(root, 0, arr);
 
    bool nullFound = false;
    int ans = 0;
 
    for (auto& it : arr) {
 
        // If the array value is -1
        // means node is null
        if (it == -1)
            nullFound = true;
 
        // If node is present after the
        // first null was found
        // increase the answer
        if (nullFound && it != -1)
            ans++;
    }
 
    return ans;
}
 
// Drivers code
int main()
{
    /*
     *          1
     *         /  \
     *        2    3
     *      /  \    \
     *     4    5     6
     *         / \
     *        7   8
     *
     *    Output: 3
     */
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);
    root->right->right = new TreeNode(6);
    root->left->right->left = new TreeNode(7);
    root->left->right->right = new TreeNode(8);
 
    cout << "Minimum number of nodes to be removed to make "
            "the tree complete is: ";
 
    // Function Call
    cout << minNodesToBeRemoved_dfs(root) << endl;
 
    return 0;
}


Java




// Java code to implement the above approach
import java.util.Arrays;
 
class GFG {
    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
 
        TreeNode(int x)
        {
            val = x;
            left = null;
            right = null;
        }
    }
 
    // function to calculate the height of the tree
    static int height(TreeNode root)
    {
        if (root == null)
            return 0;
        return 1
            + Math.max(height(root.left),
                       height(root.right));
    }
 
    // dfs traversal to fill the array
    static void dfs(TreeNode root, int index, int[] arr)
    {
        if (root == null)
            return;
 
        arr[index] = root.val;
        dfs(root.left, 2 * index + 1, arr);
        dfs(root.right, 2 * index + 2, arr);
    }
 
    static int minNodesToBeRemoved_dfs(TreeNode root)
    {
        int h = height(root);
        // find the size of the array
        int maxNodes = (1 << h) - 1;
 
        // make an array to store the nodes level wise
        int[] arr = new int[maxNodes];
        Arrays.fill(arr, -1);
 
        // dfs call
        dfs(root, 0, arr);
 
        boolean nullFound = false;
        int ans = 0;
 
        for (int i = 0; i < arr.length; i++) {
            int it = arr[i];
            // if the array value is -1 means node is null
            if (it == -1)
                nullFound = true;
            // if node is present after the first null was
            // found increase the answer
            if (nullFound && it != -1)
                ans++;
        }
 
        return ans;
    }
 
    public static void main(String[] args)
    {
        /*
         *          1
         *         /  \
         *        2    3
         *      /  \    \
         *     4    5     6
         *         / \
         *        7   8
         *
         *    Output: 3
         */
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);
        root.right.right = new TreeNode(6);
        root.left.right.left = new TreeNode(7);
        root.left.right.right = new TreeNode(8);
 
        System.out.print(
            "Minimum number of nodes to be removed to make the tree complete is: ");
        System.out.println(minNodesToBeRemoved_dfs(root));
    }
}


Python3




# Python3 code for the above approach
 
# Definition for a binary tree node
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
 
# Function to calculate the
# height of the tree
def height(root):
    if not root:
        return 0
    return 1 + max(height(root.left), height(root.right))
 
# dfs traversal to fill the array
def dfs(root, index, arr):
    if not root:
        return
    arr[index] = root.val
    dfs(root.left, 2 * index + 1, arr)
    dfs(root.right, 2 * index + 2, arr)
 
def minNodesToBeRemoved_dfs(root):
    h = height(root)
 
    # Find the size of the array
    maxNodes = (1 << h) - 1
 
    # Make an array to store the
    # nodes level wise
    arr = [-1] * maxNodes
 
    # dfs call
    dfs(root, 0, arr)
 
    nullFound = False
    ans = 0
 
    for it in arr:
        # If the array value is -1
        # means node is null
        if it == -1:
            nullFound = True
 
        # If node is present after the
        # first null was found
        # increase the answer
        if nullFound and it != -1:
            ans += 1
 
    return ans
 
# Drivers code
if __name__ == "__main__":
    """
            1
           /  \
          2    3
        /  \    \
       4    5     6
           / \
          7   8
 
       Output: 3
    """
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(3)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(5)
    root.right.right = TreeNode(6)
    root.left.right.left = TreeNode(7)
    root.left.right.right = TreeNode(8)
 
    print("Minimum number of nodes to be removed to make the tree complete is: ")
 
    # Function Call
    print(minNodesToBeRemoved_dfs(root))


C#




// C# code for the above approach
 
using System;
using System.Collections.Generic;
 
// Definition for a binary tree node
public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
     
    public TreeNode(int x) {
        val = x;
        left = null;
        right = null;
    }
}
 
public class Solution {
     
    // Function to calculate the height of the tree
    public int Height(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return 1 + Math.Max(Height(root.left), Height(root.right));
    }
     
    // dfs traversal to fill the array
    public void Dfs(TreeNode root, int index, List<int> arr) {
        if (root == null) {
            return;
        }
        arr[index] = root.val;
        Dfs(root.left, 2 * index + 1, arr);
        Dfs(root.right, 2 * index + 2, arr);
    }
     
    public int MinNodesToBeRemoved(TreeNode root) {
        int h = Height(root);
         
        // Find the size of the array
        int maxNodes = (1 << h) - 1;
         
        // Make an array to store the nodes level wise
        List<int> arr = new List<int>(maxNodes);
        for (int i = 0; i < maxNodes; i++) {
            arr.Add(-1);
        }
         
        // dfs call
        Dfs(root, 0, arr);
         
        bool nullFound = false;
        int ans = 0;
         
        foreach (int it in arr) {
            // If the array value is -1 means node is null
            if (it == -1) {
                nullFound = true;
            }
            // If node is present after the first null was found
            // increase the answer
            if (nullFound && it != -1) {
                ans++;
            }
        }
        return ans;
    }
     
    // Drivers code
    static void Main() {
        /*
        *         1
        *         / \
        *     2 3
        *     / \ \
        *     4 5     6
        *         / \
        *     7 8
        *
        * Output: 3
        */
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);
        root.right.right = new TreeNode(6);
        root.left.right.left = new TreeNode(7);
        root.left.right.right = new TreeNode(8);
         
        Console.Write("Minimum number of nodes to be removed to make " +
                      "the tree complete is: ");
         
        // Function Call
        Console.WriteLine(new Solution().MinNodesToBeRemoved(root));
    }
}


Javascript




// Javascript code for the above approach
 
// Definition for a binary tree node
class TreeNode {
  constructor(val) {
    this.val = val;
    this.left = null;
    this.right = null;
  }
}
 
// Function to calculate the height of the tree
function height(root) {
  if (!root) {
    return 0;
  }
  return 1 + Math.max(height(root.left), height(root.right));
}
 
// dfs traversal to fill the array
function dfs(root, index, arr) {
  if (!root) {
    return;
  }
 
  arr[index] = root.val;
  dfs(root.left, 2 * index + 1, arr);
  dfs(root.right, 2 * index + 2, arr);
}
 
function minNodesToBeRemoved_dfs(root) {
  const h = height(root);
 
  // Find the size of the array
  const maxNodes = (1 << h) - 1;
 
  // Make an array to store the nodes level wise
  const arr = new Array(maxNodes).fill(-1);
 
  // dfs call
  dfs(root, 0, arr);
 
  let nullFound = false;
  let ans = 0;
 
  for (let i = 0; i < arr.length; i++) {
    const it = arr[i];
 
    // If the array value is -1
    // means node is null
    if (it === -1) {
      nullFound = true;
    }
 
    // If node is present after the
    // first null was found
    // increase the answer
    if (nullFound && it !== -1) {
      ans++;
    }
  }
 
  return ans;
}
 
// Drivers code
function main() {
  /*
  *      1
  *     / \
  *    2   3
  *   / \   \
  *  4   5   6
  *         / \
  *        7   8
  *
  * Output: 3
  */
  const root = new TreeNode(1);
  root.left = new TreeNode(2);
  root.right = new TreeNode(3);
  root.left.left = new TreeNode(4);
  root.left.right = new TreeNode(5);
  root.right.right = new TreeNode(6);
  root.left.right.left = new TreeNode(7);
  root.left.right.right = new TreeNode(8);
 
  console.log(
    "Minimum number of nodes to be removed to make " +
      "the tree complete is: " +
      minNodesToBeRemoved_dfs(root)
  );
}
 
main();


Output

Minimum number of nodes to be removed to make the tree complete is: 3

Time Complexity: O(2^h-1), where h is the height of the tree.
Auxiliary Space: O(2^h-1)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads