|
| 1 | +<h1 align='center'>Largest - BST</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Largest BST](https://www.geeksforgeeks.org/problems/largest-bst/1) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +## Problem Explanation |
| 11 | +The task is to find the size of the largest Binary Search Tree (BST) within a binary tree. |
| 12 | + |
| 13 | +- A **Binary Search Tree (BST)** is a binary tree where each node's value must be greater than all values in its left subtree and less than all values in its right subtree. |
| 14 | +- The "size" of a tree (or subtree) is the number of nodes it contains. |
| 15 | + |
| 16 | +Given a binary tree, we need to find the largest subset of nodes that form a BST. |
| 17 | + |
| 18 | +#### Example for Better Understanding |
| 19 | + |
| 20 | +Consider the following binary tree: |
| 21 | + |
| 22 | +``` |
| 23 | + 10 |
| 24 | + / \ |
| 25 | + 5 15 |
| 26 | + / \ \ |
| 27 | + 1 8 20 |
| 28 | +``` |
| 29 | + |
| 30 | +Here, the subtree rooted at node `5` (`5 -> 1, 8`) forms a BST with size `3`. Similarly, the subtree rooted at `15` (`15 -> 20`) is also a BST with size `2`. The largest BST here is the subtree rooted at `5`, so the expected output is `3`. |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +### Step 2: Approach to Solve the Problem |
| 35 | + |
| 36 | +#### Understanding the Approach |
| 37 | + |
| 38 | +The idea is to recursively traverse each node in the binary tree and check whether the subtree rooted at that node forms a BST. While doing so: |
| 39 | +1. Track the minimum and maximum values in each subtree. |
| 40 | +2. Check the validity of the BST by comparing the values with left and right subtrees. |
| 41 | + |
| 42 | +For each node: |
| 43 | +- If both the left and right subtrees are BSTs, and the current node's value is greater than the maximum value of the left subtree and less than the minimum value of the right subtree, then the subtree rooted at this node is a BST. |
| 44 | +- If it forms a BST, we calculate its size by summing up the sizes of left and right subtrees and adding one for the current node. |
| 45 | + |
| 46 | +#### Example of Approach |
| 47 | + |
| 48 | +In the binary tree: |
| 49 | + |
| 50 | +``` |
| 51 | + 10 |
| 52 | + / \ |
| 53 | + 5 15 |
| 54 | + / \ \ |
| 55 | + 1 8 20 |
| 56 | +``` |
| 57 | + |
| 58 | +- For each node, recursively check if its left and right children form valid BSTs. |
| 59 | +- Track the minimum and maximum values in each subtree to determine if the current subtree satisfies BST properties. |
| 60 | +- For example, at node `5`, both children (`1` and `8`) satisfy the BST properties, so we calculate its size as `3`. |
| 61 | + |
| 62 | +## Problem Solution |
| 63 | +```cpp |
| 64 | +class info { |
| 65 | +public: |
| 66 | + int mini; |
| 67 | + int maxi; |
| 68 | + bool isBST; |
| 69 | + int size; |
| 70 | +}; |
| 71 | + |
| 72 | +class Solution { |
| 73 | +public: |
| 74 | + info getLargestBSTInfo(Node* root, int &ans) { |
| 75 | + if (root == NULL) return info{INT_MAX, INT_MIN, true, 0}; |
| 76 | + |
| 77 | + info left = getLargestBSTInfo(root->left, ans); |
| 78 | + info right = getLargestBSTInfo(root->right, ans); |
| 79 | + |
| 80 | + info currNode; |
| 81 | + currNode.size = left.size + right.size + 1; |
| 82 | + currNode.maxi = max(root->data, right.maxi); |
| 83 | + currNode.mini = min(root->data, left.mini); |
| 84 | + |
| 85 | + if (left.isBST && right.isBST && (root->data > left.maxi && root->data < right.mini)) { |
| 86 | + currNode.isBST = true; |
| 87 | + } else { |
| 88 | + currNode.isBST = false; |
| 89 | + } |
| 90 | + |
| 91 | + if (currNode.isBST) ans = max(ans, currNode.size); |
| 92 | + |
| 93 | + return currNode; |
| 94 | + } |
| 95 | + |
| 96 | + int largestBst(Node* root) { |
| 97 | + int maxSize = 0; |
| 98 | + getLargestBSTInfo(root, maxSize); |
| 99 | + return maxSize; |
| 100 | + } |
| 101 | +}; |
| 102 | + |
| 103 | +``` |
| 104 | +
|
| 105 | +## Problem Solution Explanation |
| 106 | +
|
| 107 | +```cpp |
| 108 | +class info { |
| 109 | +public: |
| 110 | + int mini; |
| 111 | + int maxi; |
| 112 | + bool isBST; |
| 113 | + int size; |
| 114 | +}; |
| 115 | +``` |
| 116 | + |
| 117 | +- **Purpose of `info` Class**: This helper class stores information about each node in the binary tree. |
| 118 | + - `mini` and `maxi` track the minimum and maximum values of the subtree rooted at each node. |
| 119 | + - `isBST` is a flag to determine if the subtree rooted at the node forms a BST. |
| 120 | + - `size` represents the number of nodes in the subtree. |
| 121 | + |
| 122 | +```cpp |
| 123 | +class Solution { |
| 124 | +public: |
| 125 | + info getLargestBSTInfo(Node* root, int &ans) { |
| 126 | + if(root == NULL) return info{INT_MAX, INT_MIN, true, 0}; |
| 127 | +``` |
| 128 | +
|
| 129 | +- **Base Case**: If `root` is `NULL`, return an `info` object for an empty subtree: |
| 130 | + - `mini = INT_MAX` and `maxi = INT_MIN` ensure that they don’t interfere with comparisons. |
| 131 | + - `isBST = true` because an empty tree is considered a BST. |
| 132 | + - `size = 0` as there are no nodes in an empty subtree. |
| 133 | +
|
| 134 | +```cpp |
| 135 | + info left = getLargestBSTInfo(root->left, ans); |
| 136 | + info right = getLargestBSTInfo(root->right, ans); |
| 137 | +``` |
| 138 | + |
| 139 | +- **Recursive Calls**: We recursively call `getLargestBSTInfo` on the left and right children to gather information on each subtree. |
| 140 | + |
| 141 | +```cpp |
| 142 | + info currNode; |
| 143 | + currNode.size = left.size + right.size + 1; |
| 144 | + currNode.maxi = max(root->data, right.maxi); |
| 145 | + currNode.mini = min(root->data, left.mini); |
| 146 | +``` |
| 147 | + |
| 148 | +- **Current Node Calculation**: |
| 149 | + - `currNode.size` is the size of the subtree rooted at the current node, calculated by summing up the sizes of the left and right subtrees and adding one for the current node itself. |
| 150 | + - `currNode.maxi` and `currNode.mini` update the maximum and minimum values within the subtree. |
| 151 | + |
| 152 | +```cpp |
| 153 | + if (left.isBST && right.isBST && (root->data > left.maxi && root->data < right.mini)) { |
| 154 | + currNode.isBST = true; |
| 155 | + } else { |
| 156 | + currNode.isBST = false; |
| 157 | + } |
| 158 | +``` |
| 159 | +
|
| 160 | +- **BST Check**: We check if both left and right subtrees are BSTs and if the current node satisfies the BST property with its children. If true, `currNode.isBST` is set to true. |
| 161 | +
|
| 162 | +```cpp |
| 163 | + if (currNode.isBST) ans = max(ans, currNode.size); |
| 164 | +``` |
| 165 | + |
| 166 | +- **Update Largest BST Size**: If `currNode` is a BST, we update the answer with the maximum size found so far. |
| 167 | + |
| 168 | +```cpp |
| 169 | + return currNode; |
| 170 | + } |
| 171 | +``` |
| 172 | + |
| 173 | +- **Return `currNode`**: Return the `info` object for the current node to be used in calculations up the recursive stack. |
| 174 | + |
| 175 | +```cpp |
| 176 | + int largestBst(Node* root) { |
| 177 | + int maxSize = 0; |
| 178 | + getLargestBSTInfo(root, maxSize); |
| 179 | + return maxSize; |
| 180 | + } |
| 181 | +}; |
| 182 | +``` |
| 183 | +
|
| 184 | +- **Main Function (`largestBst`)**: |
| 185 | + - This function initializes `maxSize` to zero and calls `getLargestBSTInfo`. |
| 186 | + - Finally, it returns the largest BST size found. |
| 187 | +
|
| 188 | +
|
| 189 | +
|
| 190 | +### Step 4: Example Walkthrough |
| 191 | +
|
| 192 | +Let's apply this on our sample tree: |
| 193 | +
|
| 194 | +``` |
| 195 | + 10 |
| 196 | + / \ |
| 197 | + 5 15 |
| 198 | + / \ \ |
| 199 | + 1 8 20 |
| 200 | +``` |
| 201 | +
|
| 202 | +1. **Node `1`** and `8`: Both are leaf nodes and satisfy BST conditions. |
| 203 | +2. **Node `5`**: Receives info from `1` and `8` (both BSTs), checks `5 > 1` and `5 < 8`, confirming it as a BST with size `3`. |
| 204 | +3. **Node `15`** and `20`: Both satisfy BST conditions. |
| 205 | +4. **Node `10`**: Combines info from `5` and `15`, confirms it as BST with size `6`. |
| 206 | +
|
| 207 | +Output: The largest BST has `size = 3` (rooted at `5`). |
| 208 | +
|
| 209 | +
|
| 210 | +### Step 5: Time and Space Complexity |
| 211 | +
|
| 212 | +1. **Time Complexity**: `O(N)` where `N` is the number of nodes. Each node is visited once, gathering information on its subtrees. |
| 213 | +2. **Space Complexity**: `O(H)`, where `H` is the height of the tree due to the recursion stack. |
| 214 | +
|
| 215 | +
|
| 216 | +### Step 6: Recommendations |
| 217 | +
|
| 218 | +- **Practice Recursive BST Validation**: This problem reinforces understanding of how BST properties work. |
| 219 | +- **Explore Edge Cases**: Test with trees that contain duplicate values, single nodes, and completely balanced trees to deepen understanding. |
| 220 | +
|
| 221 | +This step-by-step explanation should help you grasp the code flow and logic for finding the largest BST in a binary tree. |
0 commit comments