|
| 1 | +<h1 align='center'>Construct - Tree - From - In-Order & Pre-Order</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Construct Tree From In-Order & Pre-Order](https://www.geeksforgeeks.org/problems/construct-tree-1/1?itm_source=geeksforgeeks&itm_medium=article&itm_campaign=practice_card) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Problem Explanation |
| 11 | +The problem is to construct a binary tree given two arrays: |
| 12 | +1. `inorder[]`: The inorder traversal of the tree. |
| 13 | +2. `preorder[]`: The preorder traversal of the tree. |
| 14 | + |
| 15 | +### Example |
| 16 | +Consider the following arrays: |
| 17 | +- `inorder[] = {4, 2, 5, 1, 6, 3}` |
| 18 | +- `preorder[] = {1, 2, 4, 5, 3, 6}` |
| 19 | + |
| 20 | +**Output**: The constructed binary tree should look like this: |
| 21 | + |
| 22 | +``` |
| 23 | + 1 |
| 24 | + / \ |
| 25 | + 2 3 |
| 26 | + / \ \ |
| 27 | + 4 5 6 |
| 28 | +``` |
| 29 | + |
| 30 | +### Constraints |
| 31 | +- The size of the input arrays will be between 1 and \(10^4\). |
| 32 | +- All values in the tree are unique. |
| 33 | + |
| 34 | +### Edge Cases |
| 35 | +- If the tree is empty, both `inorder` and `preorder` will be empty arrays. |
| 36 | +- Trees with only one node should be handled properly. |
| 37 | + |
| 38 | +## Step 2: Approach |
| 39 | + |
| 40 | +### High-Level Overview |
| 41 | +To reconstruct the tree, we can utilize the properties of the preorder and inorder traversals: |
| 42 | +- In a preorder traversal, the first element is always the root of the tree. |
| 43 | +- In an inorder traversal, the elements to the left of the root form the left subtree, and the elements to the right form the right subtree. |
| 44 | + |
| 45 | +### Step-by-Step Breakdown |
| 46 | +1. **Create a mapping** of each element in the inorder array to its index for quick lookup. This helps in identifying the left and right subtree boundaries quickly. |
| 47 | +2. **Recursively build the tree**: |
| 48 | + - Start from the first element of the preorder array as the root. |
| 49 | + - Use the mapping to find the index of the root in the inorder array. |
| 50 | + - Recursively build the left and right subtrees using the boundaries derived from the inorder array. |
| 51 | + |
| 52 | +### Pseudocode |
| 53 | +``` |
| 54 | +function buildTree(inorder[], preorder[], n): |
| 55 | + createMapping(inorder[], nodeToIndex) |
| 56 | + return solve(preorder[], 0, n-1) |
| 57 | +
|
| 58 | +function solve(preorder[], index, inOrderStart, inOrderEnd): |
| 59 | + if index >= n or inOrderStart > inOrderEnd: |
| 60 | + return NULL |
| 61 | + element = preorder[index] |
| 62 | + root = new Node(element) |
| 63 | + position = nodeToIndex[element] |
| 64 | + root.left = solve(preorder[], index+1, inOrderStart, position-1) |
| 65 | + root.right = solve(preorder[], index+1, position+1, inOrderEnd) |
| 66 | + return root |
| 67 | +``` |
| 68 | + |
| 69 | +## Problem Solution |
| 70 | +```cpp |
| 71 | +class Solution{ |
| 72 | + public: |
| 73 | + |
| 74 | + void createMapping(int in[], map<int, int> &nodeToIndex, int n){ |
| 75 | + for(int i = 0; i < n; i++){ |
| 76 | + nodeToIndex[in[i]] = i; |
| 77 | + } |
| 78 | + |
| 79 | + } |
| 80 | + |
| 81 | + Node* solve(int in[], int pre[], int &index, int inOrderStart, int inOrderEnd, int n, map<int, int> &nodeToIndex){ |
| 82 | + if(index >= n || inOrderStart > inOrderEnd) return NULL; |
| 83 | + |
| 84 | + int element = pre[index++]; |
| 85 | + Node* root = new Node(element); |
| 86 | + |
| 87 | + int position = nodeToIndex[element]; |
| 88 | + |
| 89 | + root->left = solve(in, pre, index, inOrderStart, position - 1, n, nodeToIndex); |
| 90 | + root->right = solve(in, pre, index, position + 1, inOrderEnd, n, nodeToIndex); |
| 91 | + |
| 92 | + return root; |
| 93 | + } |
| 94 | + |
| 95 | + Node* buildTree(int in[],int pre[], int n) |
| 96 | + { |
| 97 | + int preOrderIndex = 0; |
| 98 | + map<int, int> nodeToIndex; |
| 99 | + createMapping(in, nodeToIndex, n); |
| 100 | + |
| 101 | + return solve(in, pre, preOrderIndex, 0, n-1, n, nodeToIndex); |
| 102 | + |
| 103 | + } |
| 104 | +}; |
| 105 | +``` |
| 106 | +
|
| 107 | +## Problem Solution Explanation |
| 108 | +
|
| 109 | +Here's the code again for reference: |
| 110 | +
|
| 111 | +1. **Class Declaration**: |
| 112 | + ```cpp |
| 113 | + class Solution { |
| 114 | + public: |
| 115 | + ``` |
| 116 | + - Defines a class named `Solution` that contains methods to solve the problem. |
| 117 | + |
| 118 | +2. **Mapping Creation**: |
| 119 | + ```cpp |
| 120 | + void createMapping(int in[], map<int, int> &nodeToIndex, int n) { |
| 121 | + ``` |
| 122 | + - This method creates a mapping of each value in the `inorder` array to its index. |
| 123 | +
|
| 124 | +3. **Filling the Map**: |
| 125 | + ```cpp |
| 126 | + for (int i = 0; i < n; i++) { |
| 127 | + nodeToIndex[in[i]] = i; |
| 128 | + } |
| 129 | + ``` |
| 130 | + - Iterates through the `inorder` array and fills the `nodeToIndex` map with each element's value as the key and its index as the value. |
| 131 | + |
| 132 | +4. **Recursive Solve Function**: |
| 133 | + ```cpp |
| 134 | + Node* solve(int in[], int pre[], int &index, int inOrderStart, int inOrderEnd, int n, map<int, int> &nodeToIndex) { |
| 135 | + ``` |
| 136 | + - This method constructs the binary tree recursively. |
| 137 | +
|
| 138 | +5. **Base Case**: |
| 139 | + ```cpp |
| 140 | + if (index >= n || inOrderStart > inOrderEnd) return NULL; |
| 141 | + ``` |
| 142 | + - Checks if the index has gone out of bounds or if the current subtree is invalid. If so, it returns `NULL`. |
| 143 | + |
| 144 | +6. **Element Extraction**: |
| 145 | + ```cpp |
| 146 | + int element = pre[index++]; |
| 147 | + Node* root = new Node(element); |
| 148 | + ``` |
| 149 | + - Gets the current root element from the preorder array and creates a new `Node` for it. The index is incremented for the next recursive call. |
| 150 | + |
| 151 | +7. **Finding Position in Inorder**: |
| 152 | + ```cpp |
| 153 | + int position = nodeToIndex[element]; |
| 154 | + ``` |
| 155 | + - Finds the index of the current root in the inorder array using the previously created mapping. |
| 156 | + |
| 157 | +8. **Building Left Subtree**: |
| 158 | + ```cpp |
| 159 | + root->left = solve(in, pre, index, inOrderStart, position - 1, n, nodeToIndex); |
| 160 | + ``` |
| 161 | + - Recursively calls `solve` to build the left subtree using the left part of the inorder array (from `inOrderStart` to `position - 1`). |
| 162 | + |
| 163 | +9. **Building Right Subtree**: |
| 164 | + ```cpp |
| 165 | + root->right = solve(in, pre, index, position + 1, inOrderEnd, n, nodeToIndex); |
| 166 | + ``` |
| 167 | + - Recursively calls `solve` to build the right subtree using the right part of the inorder array (from `position + 1` to `inOrderEnd`). |
| 168 | + |
| 169 | +10. **Returning the Root**: |
| 170 | + ```cpp |
| 171 | + return root; |
| 172 | + ``` |
| 173 | + - Returns the constructed subtree rooted at the current `root`. |
| 174 | + |
| 175 | +11. **Building the Tree**: |
| 176 | + ```cpp |
| 177 | + Node* buildTree(int in[], int pre[], int n) { |
| 178 | + int preOrderIndex = 0; |
| 179 | + map<int, int> nodeToIndex; |
| 180 | + createMapping(in, nodeToIndex, n); |
| 181 | + |
| 182 | + return solve(in, pre, preOrderIndex, 0, n - 1, n, nodeToIndex); |
| 183 | + } |
| 184 | + ``` |
| 185 | + - Initializes the `preOrderIndex` to `0`, creates the mapping using `createMapping`, and starts the recursive process to build the tree. |
| 186 | + |
| 187 | +## Step 4: Output Examples |
| 188 | + |
| 189 | +Let's consider the following input: |
| 190 | + |
| 191 | +### Input |
| 192 | +- `inorder[] = {4, 2, 5, 1, 6, 3}` |
| 193 | +- `preorder[] = {1, 2, 4, 5, 3, 6}` |
| 194 | + |
| 195 | +### Execution Steps |
| 196 | +1. Call `buildTree` with the given `inorder` and `preorder`. |
| 197 | +2. The mapping created will be: |
| 198 | + ``` |
| 199 | + 4 -> 0 |
| 200 | + 2 -> 1 |
| 201 | + 5 -> 2 |
| 202 | + 1 -> 3 |
| 203 | + 6 -> 4 |
| 204 | + 3 -> 5 |
| 205 | + ``` |
| 206 | +3. The recursive calls will process as follows: |
| 207 | + - Root is `1`, left subtree: `2`, right subtree: `3`. |
| 208 | + - Further decomposing `2` gives us `4` and `5`. |
| 209 | + - Finally, `3` leads to `6`. |
| 210 | + |
| 211 | +### Output |
| 212 | +The constructed tree will be: |
| 213 | + |
| 214 | +``` |
| 215 | + 1 |
| 216 | + / \ |
| 217 | + 2 3 |
| 218 | + / \ \ |
| 219 | + 4 5 6 |
| 220 | +``` |
| 221 | + |
| 222 | +## Step 5: Time and Space Complexity |
| 223 | + |
| 224 | +### Time Complexity |
| 225 | +- **Mapping Creation**: \(O(n)\), where \(n\) is the number of nodes, since we are iterating over the inorder array once. |
| 226 | +- **Recursive Tree Construction**: Each node is processed once, leading to \(O(n)\). |
| 227 | +- **Total Time Complexity**: \(O(n)\) for the entire operation. |
| 228 | + |
| 229 | +### Space Complexity |
| 230 | +- **Auxiliary Space**: The recursive call stack can go up to \(O(h)\), where \(h\) is the height of the tree. In the worst case (for a skewed tree), this can be \(O(n)\). The map for storing indices requires \(O(n)\). |
| 231 | +- **Total Space Complexity**: \(O(n)\) in the worst case. |
| 232 | + |
| 233 | +### Summary |
| 234 | +The solution efficiently constructs a binary tree from given inorder and preorder traversals by leveraging the properties of these traversals and using a map for quick index lookups. The time complexity is linear, making this approach suitable for larger trees. |
| 235 | + |
| 236 | +If you have any further questions or need additional clarification, feel free to ask! |
0 commit comments