|
| 1 | +<h1 align='center'>Balance - a Binary - Search - Tree</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Balance a Binary Search Tree](https://leetcode.com/problems/balance-a-binary-search-tree/) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Problem Explanation |
| 11 | +Given a **Binary Search Tree (BST)**, the task is to convert it into a **balanced BST**. A balanced BST ensures that the height difference between the left and right subtrees of any node is no more than 1. This balancing helps keep the search operations efficient. |
| 12 | + |
| 13 | +#### Approach to Solve the Problem |
| 14 | + |
| 15 | +1. **In-Order Traversal**: |
| 16 | + - Performing an in-order traversal of a BST visits nodes in ascending order. We store these nodes in an array or vector. |
| 17 | + - This array will contain the sorted values of the BST nodes. |
| 18 | + |
| 19 | +2. **Rebuild the Balanced BST**: |
| 20 | + - Using the sorted array from the in-order traversal, we can build a balanced BST by picking the middle element as the root of each subtree. This middle element division helps keep the BST balanced. |
| 21 | + - By recursively choosing the middle element of each subarray, we ensure each subtree is balanced. |
| 22 | + |
| 23 | +#### Example |
| 24 | + |
| 25 | +Consider a skewed BST like this: |
| 26 | +``` |
| 27 | + 10 |
| 28 | + \ |
| 29 | + 20 |
| 30 | + \ |
| 31 | + 30 |
| 32 | + \ |
| 33 | + 40 |
| 34 | +``` |
| 35 | + |
| 36 | +Performing an in-order traversal on this BST gives the array `[10, 20, 30, 40]`. |
| 37 | + |
| 38 | +Rebuilding this as a balanced BST gives: |
| 39 | +``` |
| 40 | + 20 |
| 41 | + / \ |
| 42 | + 10 30 |
| 43 | + \ |
| 44 | + 40 |
| 45 | +``` |
| 46 | + |
| 47 | +This balanced BST has a reduced height, making it more efficient for search operations. |
| 48 | + |
| 49 | +## Problem Solution |
| 50 | +```cpp |
| 51 | +/** |
| 52 | + * Definition for a binary tree node. |
| 53 | + * struct TreeNode { |
| 54 | + * int val; |
| 55 | + * TreeNode *left; |
| 56 | + * TreeNode *right; |
| 57 | + * TreeNode() : val(0), left(nullptr), right(nullptr) {} |
| 58 | + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} |
| 59 | + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} |
| 60 | + * }; |
| 61 | + */ |
| 62 | +class Solution { |
| 63 | +public: |
| 64 | + void inOrder(TreeNode* root, vector<TreeNode*> &inOrderValues){ |
| 65 | + if(root == NULL) return; |
| 66 | + |
| 67 | + inOrder(root -> left, inOrderValues); |
| 68 | + inOrderValues.push_back(root); |
| 69 | + inOrder(root -> right, inOrderValues); |
| 70 | + } |
| 71 | + |
| 72 | + TreeNode* inorderToBST(int start, int end, vector<TreeNode*> &inOrderValues){ |
| 73 | + if(start > end) return NULL; |
| 74 | + |
| 75 | + int mid = start + (end - start) / 2; |
| 76 | + |
| 77 | + TreeNode* root = inOrderValues[mid]; |
| 78 | + |
| 79 | + root -> left = inorderToBST(start, mid-1, inOrderValues); |
| 80 | + root -> right = inorderToBST(mid + 1, end, inOrderValues); |
| 81 | + |
| 82 | + return root; |
| 83 | + } |
| 84 | + TreeNode* balanceBST(TreeNode* root) { |
| 85 | + vector<TreeNode*> inOrderValues; |
| 86 | + inOrder(root, inOrderValues); |
| 87 | + |
| 88 | + return inorderToBST(0, inOrderValues.size()-1, inOrderValues); |
| 89 | + } |
| 90 | +}; |
| 91 | +``` |
| 92 | +
|
| 93 | +## Problem Solution Explanation |
| 94 | +
|
| 95 | +```cpp |
| 96 | +class Solution { |
| 97 | +public: |
| 98 | +``` |
| 99 | +- Defines the `Solution` class with public member functions. |
| 100 | + |
| 101 | +```cpp |
| 102 | + void inOrder(TreeNode* root, vector<TreeNode*> &inOrderValues){ |
| 103 | + if(root == NULL) return; |
| 104 | +``` |
| 105 | +- `inOrder` is a helper function to perform an in-order traversal of the BST. |
| 106 | +- If `root` is `NULL`, it means there are no nodes to process, so it immediately returns. |
| 107 | +
|
| 108 | +```cpp |
| 109 | + inOrder(root -> left, inOrderValues); |
| 110 | + inOrderValues.push_back(root); |
| 111 | + inOrder(root -> right, inOrderValues); |
| 112 | + } |
| 113 | +``` |
| 114 | +- This function recursively traverses the left subtree, then adds the current node (`root`) to the vector `inOrderValues`, and finally traverses the right subtree. |
| 115 | +- The result is a sorted vector `inOrderValues` containing all nodes in ascending order. |
| 116 | + |
| 117 | +```cpp |
| 118 | + TreeNode* inorderToBST(int start, int end, vector<TreeNode*> &inOrderValues){ |
| 119 | + if(start > end) return NULL; |
| 120 | +``` |
| 121 | +- `inorderToBST` is a recursive function that builds a balanced BST from the sorted nodes in `inOrderValues`. |
| 122 | +- If `start` is greater than `end`, it means there are no nodes left to form a subtree, so it returns `NULL`. |
| 123 | +
|
| 124 | +```cpp |
| 125 | + int mid = start + (end - start) / 2; |
| 126 | +``` |
| 127 | +- Calculates the middle index of the current range, which is the middle element of the sorted array. |
| 128 | +- This middle element becomes the root of the current subtree, ensuring balance. |
| 129 | + |
| 130 | +```cpp |
| 131 | + TreeNode* root = inOrderValues[mid]; |
| 132 | +``` |
| 133 | +- Sets the node at the `mid` index as the root for the current subtree. |
| 134 | + |
| 135 | +```cpp |
| 136 | + root -> left = inorderToBST(start, mid-1, inOrderValues); |
| 137 | + root -> right = inorderToBST(mid + 1, end, inOrderValues); |
| 138 | +``` |
| 139 | +- Recursively sets the `left` child to a balanced subtree from elements left of `mid`. |
| 140 | +- Recursively sets the `right` child to a balanced subtree from elements right of `mid`. |
| 141 | + |
| 142 | +```cpp |
| 143 | + return root; |
| 144 | + } |
| 145 | +``` |
| 146 | +- Returns the `root` of the subtree, which will be attached to the main balanced BST. |
| 147 | + |
| 148 | +```cpp |
| 149 | + TreeNode* balanceBST(TreeNode* root) { |
| 150 | + vector<TreeNode*> inOrderValues; |
| 151 | + inOrder(root, inOrderValues); |
| 152 | +``` |
| 153 | +- `balanceBST` is the main function to create the balanced BST. |
| 154 | +- First, it calls `inOrder` to populate `inOrderValues` with nodes in sorted order. |
| 155 | +
|
| 156 | +```cpp |
| 157 | + return inorderToBST(0, inOrderValues.size()-1, inOrderValues); |
| 158 | + } |
| 159 | +}; |
| 160 | +``` |
| 161 | +- It then calls `inorderToBST` to construct the balanced BST from `inOrderValues` and returns the root of the new balanced BST. |
| 162 | + |
| 163 | +### Step 3: Example Walkthrough |
| 164 | + |
| 165 | +Consider a skewed BST like: |
| 166 | +``` |
| 167 | + 10 |
| 168 | + \ |
| 169 | + 20 |
| 170 | + \ |
| 171 | + 30 |
| 172 | + \ |
| 173 | + 40 |
| 174 | +``` |
| 175 | + |
| 176 | +1. **In-Order Traversal**: |
| 177 | + - The `inOrder` function will populate `inOrderValues` with `[10, 20, 30, 40]`. |
| 178 | + |
| 179 | +2. **Rebuilding the Balanced BST**: |
| 180 | + - `inorderToBST(0, 3)` is called with `start = 0` and `end = 3`. |
| 181 | + - Middle index `mid = 1`, so `inOrderValues[1]` (20) becomes the root. |
| 182 | + - **Left Subtree**: `inorderToBST(0, 0)` creates a subtree with `10` as the root. |
| 183 | + - **Right Subtree**: `inorderToBST(2, 3)` creates a subtree rooted at `30`, with `40` as its right child. |
| 184 | + |
| 185 | + The resulting balanced BST is: |
| 186 | + ``` |
| 187 | + 20 |
| 188 | + / \ |
| 189 | + 10 30 |
| 190 | + \ |
| 191 | + 40 |
| 192 | + ``` |
| 193 | + |
| 194 | +### Step 4: Time and Space Complexity |
| 195 | + |
| 196 | +1. **Time Complexity**: |
| 197 | + - **In-Order Traversal**: \( O(n) \) to traverse and store nodes in `inOrderValues`. |
| 198 | + - **Balanced Tree Construction**: \( O(n) \), as each node is processed once in `inorderToBST`. |
| 199 | + - **Total Time Complexity**: \( O(n) \). |
| 200 | + |
| 201 | +2. **Space Complexity**: |
| 202 | + - **Auxiliary Space for Vector**: \( O(n) \), for `inOrderValues`. |
| 203 | + - **Recursive Call Stack**: \( O(\log n) \) for a balanced tree and up to \( O(n) \) for a skewed tree. |
| 204 | + - **Total Space Complexity**: \( O(n) \). |
| 205 | + |
| 206 | +### Step 5: Recommendations for Students |
| 207 | + |
| 208 | +- **Practice In-Order Traversal**: In-order traversal is essential for working with BSTs. Get comfortable with it, as it appears often in BST problems. |
| 209 | +- **Recursive Tree Building**: Understanding recursive tree construction from sorted lists is a valuable skill that can help in similar tree problems. |
| 210 | +- **Analyze Complexity**: Be sure to understand the time and space complexity of each function and how the recursive stack works, as this can help in optimizing solutions for larger inputs. |
0 commit comments