|
| 1 | +<h1 align='center'>Merge - Two - BST's</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Merge Two BST's](https://www.geeksforgeeks.org/problems/merge-two-bst-s/1) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Problem Explanation |
| 11 | +**Detailed Explanation of Problem Statement:** |
| 12 | + |
| 13 | +You are given two binary search trees (BSTs). A BST is a tree data structure where, for each node: |
| 14 | +- All values in the left subtree are less than the node’s value. |
| 15 | +- All values in the right subtree are greater than the node’s value. |
| 16 | + |
| 17 | +The task is to merge these two BSTs into a single sorted list. Specifically: |
| 18 | +1. We need to extract the elements from both BSTs. |
| 19 | +2. We must return a sorted list that contains all elements from both trees. |
| 20 | + |
| 21 | +**Example:** |
| 22 | +Imagine two BSTs: |
| 23 | +- BST1: 1, 3, 5 (In-order traversal gives `[1, 3, 5]`) |
| 24 | +- BST2: 2, 4, 6 (In-order traversal gives `[2, 4, 6]`) |
| 25 | + |
| 26 | +The merged output should be a single sorted list: `[1, 2, 3, 4, 5, 6]`. |
| 27 | + |
| 28 | + |
| 29 | + |
| 30 | +### Approach to Solve the Problem |
| 31 | + |
| 32 | +**Step-by-Step Approach for Beginners:** |
| 33 | + |
| 34 | +1. **Understand the Structure of BSTs**: Since we’re dealing with BSTs, remember that an in-order traversal of a BST (left-root-right) will give us a sorted list of elements. |
| 35 | + |
| 36 | +2. **In-Order Traversal for Sorted Lists**: |
| 37 | + - Perform an in-order traversal on each BST. This will produce two sorted lists, one for each tree. |
| 38 | + - Store the results of each traversal in separate arrays (`bst1` and `bst2`). |
| 39 | + |
| 40 | +3. **Merge Two Sorted Lists**: |
| 41 | + - Once you have two sorted arrays from both BSTs, the next task is to merge these arrays. |
| 42 | + - Use a technique similar to the "merge" step in merge sort to combine these two arrays into a single sorted list. |
| 43 | + |
| 44 | +4. **Return the Merged List**: |
| 45 | + - Finally, return this merged list, which will have all elements from both BSTs in sorted order. |
| 46 | + |
| 47 | +This approach leverages the fact that an in-order traversal of a BST yields a sorted sequence, and merging two sorted sequences can be done efficiently. |
| 48 | + |
| 49 | +## Problem Solution |
| 50 | +```cpp |
| 51 | +class Solution { |
| 52 | + public: |
| 53 | + void inOrder(Node* root, vector<int> &bst){ |
| 54 | + if(root == NULL) return; |
| 55 | + |
| 56 | + inOrder(root -> left, bst); |
| 57 | + bst.push_back(root -> data); |
| 58 | + inOrder(root -> right, bst); |
| 59 | + } |
| 60 | + |
| 61 | + vector<int> merge(Node *root1, Node *root2) { |
| 62 | + vector<int> bst1, bst2; |
| 63 | + |
| 64 | + inOrder(root1, bst1); |
| 65 | + inOrder(root2, bst2); |
| 66 | + |
| 67 | + vector<int> merged; |
| 68 | + |
| 69 | + int i = 0; |
| 70 | + int j = 0; |
| 71 | + while(i < bst1.size() && j < bst2.size()){ |
| 72 | + if(bst1[i] < bst2[j]){ |
| 73 | + merged.push_back(bst1[i++]); |
| 74 | + }else{ |
| 75 | + merged.push_back(bst2[j++]); |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + while(i < bst1.size()){ |
| 80 | + merged.push_back(bst1[i++]); |
| 81 | + } |
| 82 | + |
| 83 | + while(j < bst2.size()){ |
| 84 | + merged.push_back(bst2[j++]); |
| 85 | + } |
| 86 | + |
| 87 | + return merged; |
| 88 | + } |
| 89 | +}; |
| 90 | +``` |
| 91 | +
|
| 92 | +## Problem Solution Explanation |
| 93 | +Here is a detailed explanation of the source code line by line: |
| 94 | +
|
| 95 | +
|
| 96 | +#### `class Solution {` |
| 97 | +- **Line 1**: This line defines a class named `Solution`. This class encapsulates the logic for merging two binary search trees (BSTs). |
| 98 | +
|
| 99 | +
|
| 100 | +
|
| 101 | +#### `public:` |
| 102 | +- **Line 2**: Marks the section where the methods and members of the `Solution` class are accessible from outside the class. In C++, members declared as `public` can be accessed by any code. |
| 103 | +
|
| 104 | +
|
| 105 | +
|
| 106 | +#### `void inOrder(Node* root, vector<int> &bst) {` |
| 107 | +- **Line 3**: This line defines a method called `inOrder` that performs an in-order traversal of a binary tree. |
| 108 | + - `Node* root`: The root node of the binary tree. |
| 109 | + - `vector<int>& bst`: A reference to a vector of integers where the node values will be stored in sorted order. |
| 110 | +
|
| 111 | +
|
| 112 | +
|
| 113 | +#### `if (root == NULL) return;` |
| 114 | +- **Line 4**: Checks if the current node is `NULL` (i.e., the tree is empty or we've reached a leaf node). If so, the function returns without doing anything (base case for recursion). |
| 115 | +
|
| 116 | +
|
| 117 | +
|
| 118 | +#### `inOrder(root->left, bst);` |
| 119 | +- **Line 5**: Recursively calls `inOrder` on the left child of the current node (`root->left`). This step ensures that the left subtree is processed first (in-order traversal: left subtree, current node, right subtree). |
| 120 | +
|
| 121 | +
|
| 122 | +
|
| 123 | +#### `bst.push_back(root->data);` |
| 124 | +- **Line 6**: Adds the data value of the current node (`root->data`) to the vector `bst`. This happens after the left child has been processed (as part of the in-order traversal). |
| 125 | +
|
| 126 | +
|
| 127 | +
|
| 128 | +#### `inOrder(root->right, bst);` |
| 129 | +- **Line 7**: Recursively calls `inOrder` on the right child of the current node (`root->right`). This processes the right subtree after the current node's value has been added to `bst`. |
| 130 | +
|
| 131 | +#### `vector<int> merge(Node *root1, Node *root2) {` |
| 132 | +- **Line 8**: Defines the main method `merge`, which merges two BSTs (`root1` and `root2`). |
| 133 | + - `Node* root1`: The root node of the first BST. |
| 134 | + - `Node* root2`: The root node of the second BST. |
| 135 | + - This method will return a merged sorted vector containing the values of both BSTs. |
| 136 | +
|
| 137 | +
|
| 138 | +
|
| 139 | +#### `vector<int> bst1, bst2;` |
| 140 | +- **Line 9**: Declares two empty vectors, `bst1` and `bst2`, to store the in-order traversals of `root1` and `root2` respectively. |
| 141 | +
|
| 142 | +
|
| 143 | +#### `inOrder(root1, bst1);` |
| 144 | +- **Line 10**: Calls the `inOrder` method to populate `bst1` with the sorted values from the first BST (`root1`). |
| 145 | +
|
| 146 | +
|
| 147 | +
|
| 148 | +#### `inOrder(root2, bst2);` |
| 149 | +- **Line 11**: Calls the `inOrder` method to populate `bst2` with the sorted values from the second BST (`root2`). |
| 150 | +
|
| 151 | +
|
| 152 | +
|
| 153 | +#### `vector<int> merged;` |
| 154 | +- **Line 12**: Declares an empty vector `merged` to store the final merged and sorted values from both BSTs. |
| 155 | +
|
| 156 | +
|
| 157 | +
|
| 158 | +#### `int i = 0; int j = 0;` |
| 159 | +- **Line 13**: Declares two integer variables `i` and `j`, which are used as pointers to traverse the `bst1` and `bst2` vectors, respectively. |
| 160 | +
|
| 161 | +
|
| 162 | +
|
| 163 | +#### `while (i < bst1.size() && j < bst2.size()) {` |
| 164 | +- **Line 14**: Starts a `while` loop that runs until one of the vectors (`bst1` or `bst2`) is completely traversed. The loop compares the elements of both vectors to merge them in sorted order. |
| 165 | +
|
| 166 | +
|
| 167 | +
|
| 168 | +#### `if (bst1[i] < bst2[j]) {` |
| 169 | +- **Line 15**: Checks if the current element of `bst1` (`bst1[i]`) is smaller than the current element of `bst2` (`bst2[j]`). |
| 170 | +
|
| 171 | +
|
| 172 | +#### `merged.push_back(bst1[i++]);` |
| 173 | +- **Line 16**: If `bst1[i]` is smaller, it is added to the `merged` vector. The `i++` increments the pointer `i` to move to the next element in `bst1`. |
| 174 | +
|
| 175 | +
|
| 176 | +
|
| 177 | +#### `} else {` |
| 178 | +- **Line 17**: If `bst2[j]` is smaller or equal to `bst1[i]`, the program enters this block to add the element from `bst2`. |
| 179 | +
|
| 180 | +
|
| 181 | +
|
| 182 | +#### `merged.push_back(bst2[j++]);` |
| 183 | +- **Line 18**: Adds `bst2[j]` to `merged` and increments the pointer `j` to move to the next element in `bst2`. |
| 184 | +
|
| 185 | +
|
| 186 | +
|
| 187 | +#### `while (i < bst1.size()) {` |
| 188 | +- **Line 19**: After the main `while` loop, this loop checks if there are any remaining elements in `bst1` (i.e., if `i` is still less than `bst1.size()`). |
| 189 | +
|
| 190 | +
|
| 191 | +
|
| 192 | +#### `merged.push_back(bst1[i++]);` |
| 193 | +- **Line 20**: If there are remaining elements in `bst1`, they are added to `merged`. The `i++` increments the pointer `i` after adding each element. |
| 194 | +
|
| 195 | +
|
| 196 | +#### `while (j < bst2.size()) {` |
| 197 | +- **Line 21**: Similarly, this loop checks if there are any remaining elements in `bst2` (i.e., if `j` is still less than `bst2.size()`). |
| 198 | +
|
| 199 | +#### `merged.push_back(bst2[j++]);` |
| 200 | +- **Line 22**: If there are remaining elements in `bst2`, they are added to `merged`. The `j++` increments the pointer `j` after adding each element. |
| 201 | +
|
| 202 | +
|
| 203 | +#### `return merged;` |
| 204 | +- **Line 23**: After the merging process is complete, the `merged` vector containing all the elements from both BSTs in sorted order is returned. |
| 205 | +
|
| 206 | +
|
| 207 | +### Time and Space Complexity |
| 208 | +
|
| 209 | +**Time Complexity Analysis:** |
| 210 | +1. **In-Order Traversal of Each BST**: |
| 211 | + - Traversing each tree takes `O(N)` time, where `N` is the number of nodes in the BST. |
| 212 | + - Since we traverse two trees, this part takes `O(N + M)`, where `N` and `M` are the sizes of `root1` and `root2`. |
| 213 | +
|
| 214 | +2. **Merging Two Sorted Arrays**: |
| 215 | + - Merging two sorted arrays of sizes `N` and `M` takes `O(N + M)` time. |
| 216 | +
|
| 217 | +**Overall Time Complexity**: `O(N + M) + O(N + M) = O(N + M)`. |
| 218 | +
|
| 219 | +**Space Complexity Analysis:** |
| 220 | +1. **Auxiliary Space for Traversal Arrays**: |
| 221 | + - We store in-order traversals in two arrays (`bst1` and `bst2`), each taking `O(N)` and `O(M)` space. |
| 222 | + |
| 223 | +2. **Merged Array**: |
| 224 | + - We need `O(N + M)` space to store the merged array. |
| 225 | +
|
| 226 | +**Overall Space Complexity**: `O(N + M)`. |
| 227 | +
|
| 228 | +
|
| 229 | +### Additional Recommendations |
| 230 | +
|
| 231 | +For beginners: |
| 232 | +- **Practice In-Order Traversal**: Mastering this traversal will help you understand BSTs better. |
| 233 | +- **Study Merge Techniques**: This problem is similar to the merging step in merge sort, which is useful for solving problems involving two sorted lists. |
| 234 | +- **Practice Complexity Calculations**: Try calculating time and space complexities for different parts of algorithms to improve your analytical skills. |
0 commit comments