|
| 1 | +<h1 align='center'>Burning - Tree</h1> |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | + |
| 5 | +**Problem URL :** [Burning Tree](https://www.geeksforgeeks.org/problems/burning-tree/1) |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | + |
| 11 | +## Problem Explanation |
| 12 | +Let's go through each of the steps in detail to understand and explain the solution to the **Burning Tree** problem on GeeksforGeeks. |
| 13 | + |
| 14 | +--- |
| 15 | + |
| 16 | +### Step 1: Problem Statement |
| 17 | + |
| 18 | +**Problem Statement**: |
| 19 | +Given a binary tree and a target node, imagine starting a fire at the target node. Every minute, the fire spreads to adjacent nodes (left, right, and parent). We need to calculate the minimum time required for the entire tree to be burnt. |
| 20 | + |
| 21 | +**Example**: |
| 22 | +Consider a binary tree: |
| 23 | +``` |
| 24 | + 1 |
| 25 | + / \ |
| 26 | + 2 3 |
| 27 | + / \ |
| 28 | + 4 5 |
| 29 | +``` |
| 30 | +If we start the fire at node `2`, then: |
| 31 | +- At time `1`, nodes `4` and `5` catch fire. |
| 32 | +- At time `2`, nodes `1` and `3` catch fire. |
| 33 | +- The entire tree is burnt at time `2`, so the answer is `2`. |
| 34 | + |
| 35 | +**Edge Cases**: |
| 36 | +1. If the tree has only one node, the time taken would be `0`. |
| 37 | +2. If the target node is a leaf node, then the burn would spread to its parent only in the next time unit. |
| 38 | +3. If the tree is unbalanced, the solution must account for nodes at different depths from the target. |
| 39 | + |
| 40 | +--- |
| 41 | + |
| 42 | +### Step 2: Approach |
| 43 | + |
| 44 | +**High-Level Overview**: |
| 45 | +To solve this problem, we’ll use two main steps: |
| 46 | +1. **Identify the Parent of Each Node**: This will help in spreading the fire upwards towards the parent nodes. |
| 47 | +2. **Simulate the Burning Process**: Using a breadth-first search (BFS), we can track how fire spreads level by level to adjacent nodes. |
| 48 | + |
| 49 | +**Step-by-Step Breakdown**: |
| 50 | +1. **Parent Mapping**: |
| 51 | + - Traverse the tree and create a mapping of each node to its parent. |
| 52 | + - While creating the parent map, locate the target node in the tree. |
| 53 | + |
| 54 | +2. **Burn Simulation Using BFS**: |
| 55 | + - Initialize a queue with the target node and a `visited` set to track nodes that have already caught fire. |
| 56 | + - At each time unit (each BFS level), spread the fire to the node’s left, right, and parent (if they haven’t burned yet). |
| 57 | + - Count the time units until all nodes have burned. |
| 58 | + |
| 59 | +**Pseudocode**: |
| 60 | +```plaintext |
| 61 | +Function createParentMapping(root, target): |
| 62 | + Initialize queue with root, nodeToParent map, result (target node) |
| 63 | + While queue is not empty: |
| 64 | + Pop node from queue |
| 65 | + If node data equals target, set it as result |
| 66 | + For each child of node: |
| 67 | + Set node as parent in nodeToParent map |
| 68 | + Push child to queue |
| 69 | + Return result (target node) |
| 70 | +
|
| 71 | +Function burnTree(root, nodeToParent): |
| 72 | + Initialize queue with root, visited set, ans as 0 |
| 73 | + While queue is not empty: |
| 74 | + Flag to track if any new node catches fire |
| 75 | + For each node in queue: |
| 76 | + Spread fire to unvisited neighbors (left, right, parent) |
| 77 | + Set flag = true if new node catches fire |
| 78 | + If flag is true, increment ans |
| 79 | + Return ans |
| 80 | +``` |
| 81 | + |
| 82 | +## Problem Solution |
| 83 | +```cpp |
| 84 | +class Solution { |
| 85 | + public: |
| 86 | + Node* createParentMapping(Node* root, int target, unordered_map<Node*, Node*>&nodeToParent){ |
| 87 | + Node* result = NULL; |
| 88 | + queue<Node*> q; |
| 89 | + q.push(root); |
| 90 | + |
| 91 | + nodeToParent[root] = NULL; |
| 92 | + |
| 93 | + while(!q.empty()){ |
| 94 | + Node* front = q.front(); |
| 95 | + q.pop(); |
| 96 | + |
| 97 | + if(front -> data == target) result = front; |
| 98 | + |
| 99 | + if(front -> left){ |
| 100 | + nodeToParent[front -> left] = front; |
| 101 | + q.push(front -> left); |
| 102 | + } |
| 103 | + |
| 104 | + if(front -> right){ |
| 105 | + nodeToParent[front -> right] = front; |
| 106 | + q.push(front -> right); |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + return result; |
| 111 | + } |
| 112 | + |
| 113 | + int burnTree(Node* root, unordered_map<Node*, Node*> &nodeToParent){ |
| 114 | + unordered_map<Node*, bool> visited; |
| 115 | + queue<Node*> q; |
| 116 | + |
| 117 | + q.push(root); |
| 118 | + visited[root] = true; |
| 119 | + |
| 120 | + int ans = 0; |
| 121 | + |
| 122 | + while(!q.empty()){ |
| 123 | + bool flag = false; |
| 124 | + int size = q.size(); |
| 125 | + |
| 126 | + for(int i = 0; i < size; i++){ |
| 127 | + Node* front = q.front(); |
| 128 | + q.pop(); |
| 129 | + |
| 130 | + if(front -> left && !visited[front->left]){ |
| 131 | + flag = true; |
| 132 | + q.push(front -> left); |
| 133 | + visited[front -> left] = true; |
| 134 | + } |
| 135 | + |
| 136 | + if(front -> right && !visited[front -> right]){ |
| 137 | + flag = true; |
| 138 | + q.push(front -> right); |
| 139 | + visited[front -> right] = true; |
| 140 | + } |
| 141 | + |
| 142 | + if(nodeToParent[front] && !visited[nodeToParent[front]]){ |
| 143 | + flag = true; |
| 144 | + q.push(nodeToParent[front]); |
| 145 | + visited[nodeToParent[front]] = true; |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + if(flag == true) ans++; |
| 150 | + |
| 151 | + } |
| 152 | + |
| 153 | + return ans; |
| 154 | + } |
| 155 | + |
| 156 | + int minTime(Node* root, int target) |
| 157 | + { |
| 158 | + unordered_map<Node*, Node*> nodeToParent; |
| 159 | + Node* targetNode = createParentMapping(root, target, nodeToParent); |
| 160 | + |
| 161 | + return burnTree(targetNode, nodeToParent); |
| 162 | + } |
| 163 | +}; |
| 164 | +``` |
| 165 | +
|
| 166 | +## Problem Solution Explanation |
| 167 | +Let’s go through the code line-by-line, focusing on each function in detail with examples. |
| 168 | +
|
| 169 | +The solution consists of three main functions: |
| 170 | +
|
| 171 | +1. **`createParentMapping`** - Builds a map of each node to its parent and identifies the target node. |
| 172 | +2. **`burnTree`** - Uses BFS to simulate the burning process from the target node. |
| 173 | +3. **`minTime`** - Manages the process by calling both `createParentMapping` and `burnTree`. |
| 174 | +
|
| 175 | +Let’s go over each function in detail. |
| 176 | +
|
| 177 | +#### Function `createParentMapping` |
| 178 | +
|
| 179 | +```cpp |
| 180 | +Node* createParentMapping(Node* root, int target, unordered_map<Node*, Node*>& nodeToParent) { |
| 181 | + Node* result = NULL; // To store the target node once we find it |
| 182 | + queue<Node*> q; // Queue for level-order traversal |
| 183 | + q.push(root); // Start traversal from the root |
| 184 | + nodeToParent[root] = NULL; // Root has no parent, so set it to NULL |
| 185 | +``` |
| 186 | + |
| 187 | +1. **Explanation**: |
| 188 | + - We start with `result` as `NULL`, which will eventually store our target node. |
| 189 | + - A `queue` is initialized to perform a level-order traversal of the tree. |
| 190 | + - We map the `root` node’s parent as `NULL` since it has no parent. |
| 191 | + |
| 192 | +**Example**: |
| 193 | +Suppose the tree is: |
| 194 | +``` |
| 195 | + 1 |
| 196 | + / \ |
| 197 | + 2 3 |
| 198 | + / \ |
| 199 | + 4 5 |
| 200 | +``` |
| 201 | +After setting `nodeToParent[root] = NULL`, `nodeToParent` will look like: |
| 202 | +``` |
| 203 | +nodeToParent = { 1: NULL } |
| 204 | +``` |
| 205 | + |
| 206 | +```cpp |
| 207 | + while (!q.empty()) { // While there are nodes to process |
| 208 | + Node* front = q.front(); // Get the front node in the queue |
| 209 | + q.pop(); // Remove it from the queue |
| 210 | +``` |
| 211 | +
|
| 212 | +2. **Explanation**: |
| 213 | + - `front` is the current node we’re processing. |
| 214 | + - We remove `front` from the queue as we will now check its children. |
| 215 | +
|
| 216 | +```cpp |
| 217 | + if (front->data == target) result = front; // Check if this is the target node |
| 218 | +``` |
| 219 | + |
| 220 | +3. **Explanation**: |
| 221 | + - If `front` has the data equal to the target value, we store `front` in `result` as the target node. |
| 222 | + |
| 223 | +```cpp |
| 224 | + if (front->left) { // If there is a left child |
| 225 | + nodeToParent[front->left] = front; // Map it to its parent |
| 226 | + q.push(front->left); // Add left child to queue |
| 227 | + } |
| 228 | + |
| 229 | + if (front->right) { // If there is a right child |
| 230 | + nodeToParent[front->right] = front; // Map it to its parent |
| 231 | + q.push(front->right); // Add right child to queue |
| 232 | + } |
| 233 | + } |
| 234 | +``` |
| 235 | +
|
| 236 | +4. **Explanation**: |
| 237 | + - For each child (left and right) of `front`, we: |
| 238 | + - Add it to `nodeToParent` with `front` as the parent. |
| 239 | + - Add the child to the queue for processing. |
| 240 | +
|
| 241 | +**Example Continued**: |
| 242 | +Let’s assume the target node is `2`. The `nodeToParent` map will be built as: |
| 243 | +``` |
| 244 | +nodeToParent = { |
| 245 | + 1: NULL, |
| 246 | + 2: 1, |
| 247 | + 3: 1, |
| 248 | + 4: 2, |
| 249 | + 5: 2 |
| 250 | +} |
| 251 | +``` |
| 252 | + |
| 253 | +```cpp |
| 254 | + return result; // Return the target node |
| 255 | +} |
| 256 | +``` |
| 257 | + |
| 258 | +5. **Explanation**: |
| 259 | + - We return the `result`, which contains the target node. |
| 260 | + |
| 261 | + |
| 262 | +#### Function `burnTree` |
| 263 | + |
| 264 | +```cpp |
| 265 | +int burnTree(Node* root, unordered_map<Node*, Node*>& nodeToParent) { |
| 266 | + unordered_map<Node*, bool> visited; // Track which nodes have burned |
| 267 | + queue<Node*> q; // Queue for level-order burning process |
| 268 | + q.push(root); // Start burning from the target node |
| 269 | + visited[root] = true; // Mark the target node as visited |
| 270 | + int ans = 0; // Time counter for burning process |
| 271 | +``` |
| 272 | +
|
| 273 | +1. **Explanation**: |
| 274 | + - `visited` keeps track of nodes that are already burning. |
| 275 | + - `q` is initialized with the `root` (target node) to begin the burn. |
| 276 | + - `ans` keeps track of the total time needed. |
| 277 | +
|
| 278 | +```cpp |
| 279 | + while (!q.empty()) { |
| 280 | + bool flag = false; // Flag to check if any new nodes catch fire |
| 281 | + int size = q.size(); // Current level size in BFS |
| 282 | +``` |
| 283 | + |
| 284 | +2. **Explanation**: |
| 285 | + - `flag` checks if any node catches fire in the current level of the BFS. |
| 286 | + - `size` is used to process each level one by one. |
| 287 | + |
| 288 | +```cpp |
| 289 | + for (int i = 0; i < size; i++) { |
| 290 | + Node* front = q.front(); // Get the front node |
| 291 | + q.pop(); // Remove it from the queue |
| 292 | +``` |
| 293 | +
|
| 294 | +3. **Explanation**: |
| 295 | + - We process each node at the current level (`size` times). |
| 296 | +
|
| 297 | +```cpp |
| 298 | + if (front->left && !visited[front->left]) { // Check left child |
| 299 | + flag = true; // Mark that a new node caught fire |
| 300 | + q.push(front->left); // Add it to queue |
| 301 | + visited[front->left] = true; // Mark as visited |
| 302 | + } |
| 303 | + |
| 304 | + if (front->right && !visited[front->right]) { // Check right child |
| 305 | + flag = true; |
| 306 | + q.push(front->right); |
| 307 | + visited[front->right] = true; |
| 308 | + } |
| 309 | + |
| 310 | + if (nodeToParent[front] && !visited[nodeToParent[front]]) { // Check parent |
| 311 | + flag = true; |
| 312 | + q.push(nodeToParent[front]); |
| 313 | + visited[nodeToParent[front]] = true; |
| 314 | + } |
| 315 | +``` |
| 316 | + |
| 317 | +4. **Explanation**: |
| 318 | + - We check each of `front`’s neighbors (left, right, and parent) and spread the fire to unvisited nodes. |
| 319 | + - If any new node catches fire, we set `flag = true`. |
| 320 | + |
| 321 | +```cpp |
| 322 | + } |
| 323 | + |
| 324 | + if (flag) ans++; // Increase time if any node caught fire in this level |
| 325 | + } |
| 326 | + |
| 327 | + return ans; // Return the total time taken to burn the tree |
| 328 | +} |
| 329 | +``` |
| 330 | + |
| 331 | +5. **Explanation**: |
| 332 | + - If `flag` is true, increment `ans` because it indicates another minute has passed. |
| 333 | + - Return `ans` once all nodes have burned. |
| 334 | + |
| 335 | +**Example Continued**: |
| 336 | +With the tree example and target node `2`: |
| 337 | +1. **Minute 0**: `q = [2]` |
| 338 | +2. **Minute 1**: `q = [1, 4, 5]` |
| 339 | +3. **Minute 2**: `q = [3]` |
| 340 | + - All nodes have burned, so `ans = 2`. |
| 341 | + |
| 342 | +#### Function `minTime` |
| 343 | + |
| 344 | +```cpp |
| 345 | +int minTime(Node* root, int target) { |
| 346 | + unordered_map<Node*, Node*> nodeToParent; |
| 347 | + Node* targetNode = createParentMapping(root, target, nodeToParent); |
| 348 | + |
| 349 | + return burnTree(targetNode, nodeToParent); |
| 350 | +} |
| 351 | +``` |
| 352 | +
|
| 353 | +- This function: |
| 354 | + 1. Calls `createParentMapping` to get the `targetNode` and `nodeToParent` mapping. |
| 355 | + 2. Calls `burnTree` to calculate the burn time. |
| 356 | +
|
| 357 | +
|
| 358 | +### Output Examples |
| 359 | +
|
| 360 | +Example Tree: |
| 361 | +``` |
| 362 | + 1 |
| 363 | + / \ |
| 364 | + 2 3 |
| 365 | + / \ |
| 366 | + 4 5 |
| 367 | +``` |
| 368 | +
|
| 369 | +**Input**: Target node is `2`. |
| 370 | +**Output**: `2` |
| 371 | +**Explanation**: |
| 372 | +1. **Time 0**: Start burning at `2`. |
| 373 | +2. **Time 1**: Nodes `4`, `5`, and `1` catch fire. |
| 374 | +3. **Time 2**: Node `3` catches fire. All nodes have burned. |
| 375 | +
|
| 376 | +### Step 5: Time and Space Complexity |
| 377 | +
|
| 378 | +- **Time Complexity**: |
| 379 | + - `createParentMapping`: \(O(N)\) where \(N\) is the number of nodes, as we perform a single traversal. |
| 380 | + - `burnTree`: \(O(N)\), as we again traverse each node once. |
| 381 | + - **Overall**: \(O(N)\). |
| 382 | +
|
| 383 | +- **Space Complexity**: |
| 384 | + - The space complexity is \(O(N)\) for the `nodeToParent` map and `visited` set. |
| 385 | + - **Overall**: \(O(N)\). |
0 commit comments