package DataStructures.Trees; import java.util.HashMap; import java.util.Map; import DataStructures.Trees.BinaryTree.Node; /** * Approach: Naive Solution: Create root node from first value present in * preorder traversal. Look for the index of root node's value in inorder * traversal. That will tell total nodes present in left subtree and right * subtree. Based on that index create left and right subtree. * Complexity: * Time: O(n^2) for each node there is iteration to find index in inorder array * Space: Stack size = O(height) = O(lg(n)) * * Optimized Solution: Instead of iterating over inorder array to find index of * root value, create a hashmap and find out the index of root value. * Complexity: * Time: O(n) hashmap reduced iteration to find index in inorder array * Space: O(n) space taken by hashmap * */ public class CreateBinaryTreeFromInorderPreorder { public static void main(String[] args) { test(new Integer[] {}, new Integer[] {}); // empty tree test(new Integer[] { 1 }, new Integer[] { 1 }); // single node tree test(new Integer[] { 1, 2, 3, 4 }, new Integer[] { 1, 2, 3, 4 }); // right skewed tree test(new Integer[] { 1, 2, 3, 4 }, new Integer[] { 4, 3, 2, 1 }); // left skewed tree test(new Integer[] { 3, 9, 20, 15, 7 }, new Integer[] { 9, 3, 15, 20, 7 }); // normal tree } private static void test(final Integer[] preorder, final Integer[] inorder) { System.out.println("\n===================================================="); System.out.println("Naive Solution..."); BinaryTree root = new BinaryTree(createTree(preorder, inorder, 0, 0, inorder.length)); System.out.println("Preorder Traversal: "); root.preOrder(root.getRoot()); System.out.println("\nInorder Traversal: "); root.inOrder(root.getRoot()); System.out.println("\nPostOrder Traversal: "); root.postOrder(root.getRoot()); Map map = new HashMap<>(); for (int i = 0; i < inorder.length; i++) { map.put(inorder[i], i); } BinaryTree optimizedRoot = new BinaryTree(createTreeOptimized(preorder, inorder, 0, 0, inorder.length, map)); System.out.println("\n\nOptimized solution..."); System.out.println("Preorder Traversal: "); optimizedRoot.preOrder(root.getRoot()); System.out.println("\nInorder Traversal: "); optimizedRoot.inOrder(root.getRoot()); System.out.println("\nPostOrder Traversal: "); optimizedRoot.postOrder(root.getRoot()); } private static Node createTree(final Integer[] preorder, final Integer[] inorder, final int preStart, final int inStart, final int size) { if (size == 0) { return null; } Node root = new Node(preorder[preStart]); int i = inStart; while (preorder[preStart] != inorder[i]) { i++; } int leftNodesCount = i - inStart; int rightNodesCount = size - leftNodesCount - 1; root.left = createTree(preorder, inorder, preStart + 1, inStart, leftNodesCount); root.right = createTree(preorder, inorder, preStart + leftNodesCount + 1, i + 1, rightNodesCount); return root; } private static Node createTreeOptimized(final Integer[] preorder, final Integer[] inorder, final int preStart, final int inStart, final int size, final Map inorderMap) { if (size == 0) { return null; } Node root = new Node(preorder[preStart]); int i = inorderMap.get(preorder[preStart]); int leftNodesCount = i - inStart; int rightNodesCount = size - leftNodesCount - 1; root.left = createTreeOptimized(preorder, inorder, preStart + 1, inStart, leftNodesCount, inorderMap); root.right = createTreeOptimized(preorder, inorder, preStart + leftNodesCount + 1, i + 1, rightNodesCount, inorderMap); return root; } }