|
| 1 | +<h1 align="center">Maximum - Height by - Stacking - Cuboids</h1> |
| 2 | + |
| 3 | + |
| 4 | +## Problem Statement |
| 5 | + |
| 6 | +**Problem URL :** [Maximum Height By Stacking Cuboids](https://leetcode.com/problems/maximum-height-by-stacking-cuboids/description/) |
| 7 | + |
| 8 | + |
| 9 | + |
| 10 | +### Problem Explanation |
| 11 | +You are given a set of cuboids. Each cuboid has three dimensions: height, width, and length. The task is to stack these cuboids on top of each other to maximize the height of the stack. However, there are two restrictions: |
| 12 | +1. A cuboid can be rotated in any way, meaning you can swap the dimensions (height, width, length) to create different orientations. |
| 13 | +2. A cuboid can only be placed on top of another cuboid if its width and length (after rotation) are both smaller than or equal to the cuboid below it. |
| 14 | + |
| 15 | +**Objective**: |
| 16 | +Find the maximum height of the tower that can be formed by stacking the cuboids. |
| 17 | + |
| 18 | +### Step-by-Step Explanation of the Problem: |
| 19 | + |
| 20 | +#### Step 1: Understanding Cuboid Rotation |
| 21 | +For each cuboid, we can rotate it in three different ways. Each rotation changes which dimension is considered the height, width, and length. Let's take an example: |
| 22 | + |
| 23 | +- **Cuboid A**: Dimensions are [4, 1, 4]. |
| 24 | + It can be rotated to produce the following three possible orientations: |
| 25 | + - Rotation 1: [1, 4, 4] → (height = 1, width = 4, length = 4) |
| 26 | + - Rotation 2: [4, 1, 4] → (height = 4, width = 1, length = 4) |
| 27 | + - Rotation 3: [4, 4, 1] → (height = 4, width = 4, length = 1) |
| 28 | + |
| 29 | +#### Step 2: Stacking the Cuboids |
| 30 | +The goal is to stack these cuboids in a way that maximizes the total height. The rules for stacking are: |
| 31 | +- A cuboid can only be placed on top of another if: |
| 32 | + - Its width is less than or equal to the width of the cuboid below it. |
| 33 | + - Its length is less than or equal to the length of the cuboid below it. |
| 34 | + |
| 35 | +For example: |
| 36 | +- If cuboid A is [1, 4, 4] and cuboid B is [2, 5, 6], cuboid A can be placed on cuboid B because both the width (1 <= 2) and length (4 <= 5) of cuboid A are less than or equal to those of cuboid B. |
| 37 | + |
| 38 | +#### Step 3: Rotating All Cuboids |
| 39 | +To ensure we can stack cuboids in any orientation, we generate all possible rotations of each cuboid. Then, we try to stack them based on their dimensions. |
| 40 | + |
| 41 | +#### Step 4: Dynamic Programming Approach |
| 42 | +The approach uses dynamic programming (DP) to solve this problem. We can treat this as a "Longest Increasing Subsequence" problem where: |
| 43 | +- Each cuboid’s height is considered as a potential "value" in a stack. |
| 44 | +- We check if a cuboid can be placed on top of another cuboid (based on width and length). |
| 45 | +- We compute the maximum height achievable for each cuboid by including it in the stack. |
| 46 | + |
| 47 | +#### Example to Illustrate the Problem: |
| 48 | + |
| 49 | +Consider the following cuboids: |
| 50 | + |
| 51 | +```cpp |
| 52 | +cuboids = [[4, 1, 4], [6, 2, 5], [7, 3, 6]] |
| 53 | +``` |
| 54 | + |
| 55 | +1. **Rotation**: |
| 56 | + For each cuboid, we generate all possible rotations: |
| 57 | + |
| 58 | + - Cuboid 1: `[4, 1, 4]` → Rotations are `[1, 4, 4]`, `[4, 1, 4]`, `[4, 4, 1]` |
| 59 | + - Cuboid 2: `[6, 2, 5]` → Rotations are `[2, 5, 6]`, `[5, 2, 6]`, `[6, 5, 2]` |
| 60 | + - Cuboid 3: `[7, 3, 6]` → Rotations are `[3, 6, 7]`, `[6, 3, 7]`, `[7, 6, 3]` |
| 61 | + |
| 62 | +2. **Sorting the Dimensions**: |
| 63 | + We standardize each cuboid by sorting the dimensions in ascending order, ensuring that each cuboid is represented in a consistent way (width <= length <= height). |
| 64 | + |
| 65 | + After sorting each cuboid: |
| 66 | + - Cuboid 1: `[1, 4, 4]` |
| 67 | + - Cuboid 2: `[2, 5, 6]` |
| 68 | + - Cuboid 3: `[3, 6, 7]` |
| 69 | + |
| 70 | +3. **Sorting All Cuboids**: |
| 71 | + Next, we sort all cuboids lexicographically based on their dimensions to make it easier to compare and stack them. |
| 72 | + |
| 73 | + After sorting: |
| 74 | + - Sorted cuboids: `[[1, 4, 4], [2, 5, 6], [3, 6, 7]]` |
| 75 | + |
| 76 | +4. **Applying Dynamic Programming**: |
| 77 | + Now we use dynamic programming to compute the maximum height achievable by stacking the cuboids. |
| 78 | + |
| 79 | + - **Initialization**: |
| 80 | + Start with the base case where the height of the stack for each cuboid is its own height. So, `dp = [4, 6, 7]` initially. |
| 81 | + |
| 82 | + - **Checking for Stackability**: |
| 83 | + For each cuboid `i`, check if it can be placed on top of any previous cuboid `j` (i.e., the dimensions of cuboid `j` must be smaller or equal to those of cuboid `i`). |
| 84 | + |
| 85 | + - For cuboid 1 (`[2, 5, 6]`), check if cuboid 0 (`[1, 4, 4]`) can be placed under it. Since `1 <= 2`, `4 <= 5`, and `4 <= 6`, cuboid 0 can be placed under cuboid 1. So, update the height: |
| 86 | + `dp[1] = max(dp[1], dp[0] + 6) = max(6, 4 + 6) = 10`. |
| 87 | + |
| 88 | + - For cuboid 2 (`[3, 6, 7]`), check if cuboid 0 (`[1, 4, 4]`) can be placed under cuboid 2. Since `1 <= 3`, `4 <= 6`, and `4 <= 7`, cuboid 0 can be placed under cuboid 2. So, update the height: |
| 89 | + `dp[2] = max(dp[2], dp[0] + 7) = max(7, 4 + 7) = 11`. |
| 90 | + |
| 91 | + - For cuboid 2 (`[3, 6, 7]`), check if cuboid 1 (`[2, 5, 6]`) can be placed under cuboid 2. Since `2 <= 3`, `5 <= 6`, and `6 <= 7`, cuboid 1 can be placed under cuboid 2. So, update the height: |
| 92 | + `dp[2] = max(dp[2], dp[1] + 7) = max(11, 10 + 7) = 17`. |
| 93 | + |
| 94 | +5. **Final Result**: |
| 95 | + The maximum height of the stack is the maximum value in the `dp` array. So, `max(dp[0], dp[1], dp[2]) = max(4, 10, 17) = 17`. |
| 96 | + |
| 97 | +### Explanation of the Approach Used in the Given Code: |
| 98 | + |
| 99 | +1. **Sorting the Cuboids**: |
| 100 | + Each cuboid is first rotated to generate all possible orientations, and the dimensions are sorted in ascending order. This ensures that cuboids are consistently represented. |
| 101 | + |
| 102 | +2. **Dynamic Programming (DP)**: |
| 103 | + A DP array is used to store the maximum stackable height achievable with each cuboid. Initially, each cuboid's own height is considered as the base of the tower. Then, for each cuboid, the algorithm checks if it can be stacked on top of any previous cuboid and updates the DP value accordingly. |
| 104 | + |
| 105 | +3. **Sorting the Cuboids by Dimensions**: |
| 106 | + After sorting the individual cuboid dimensions, the list of cuboids is sorted lexicographically. This ensures that the cuboids are processed in a way that simplifies the stacking process. |
| 107 | + |
| 108 | +4. **Final Result**: |
| 109 | + The final answer is the maximum value in the DP array, which represents the maximum height achievable by stacking the cuboids. |
| 110 | + |
| 111 | +### Example Walkthrough: |
| 112 | +- Given cuboids: `[[4, 1, 4], [6, 2, 5], [7, 3, 6]]` |
| 113 | +- After rotations and sorting: `[[1, 4, 4], [2, 5, 6], [3, 6, 7]]` |
| 114 | +- DP steps: |
| 115 | + - `dp[0] = 4` |
| 116 | + - `dp[1] = 10` (after stacking on cuboid 0) |
| 117 | + - `dp[2] = 17` (after stacking on cuboid 1) |
| 118 | +- Final answer: `17` |
| 119 | + |
| 120 | +This approach ensures that all possible orientations and valid stackings are considered to find the maximum height. |
| 121 | + |
| 122 | +## Problem Solution |
| 123 | +```cpp |
| 124 | +class Solution { |
| 125 | +public: |
| 126 | + int solve(vector<vector<int>>& cuboids, int n) { |
| 127 | + vector<int> dp(n); // Array to store the maximum height of the tower ending at cuboid i |
| 128 | + int maxHeight = 0; // Variable to store the overall maximum height of the tower |
| 129 | + |
| 130 | + // Loop through each cuboid (i represents the current cuboid being considered for the tower) |
| 131 | + for (int i = 0; i < n; i++) { |
| 132 | + dp[i] = cuboids[i][2]; // The initial height for each cuboid is its own height (third dimension) |
| 133 | + |
| 134 | + // Try to stack the current cuboid on top of all previously considered cuboids (j represents the previous cuboid) |
| 135 | + for (int j = 0; j < i; j++) { |
| 136 | + // Check if cuboid j can fit under cuboid i by comparing the dimensions |
| 137 | + if (cuboids[j][0] <= cuboids[i][0] && // width of cuboid j <= width of cuboid i |
| 138 | + cuboids[j][1] <= cuboids[i][1] && // length of cuboid j <= length of cuboid i |
| 139 | + cuboids[j][2] <= cuboids[i][2]) { // height of cuboid j <= height of cuboid i |
| 140 | + // If it fits, update the dp value for cuboid i to include the height of cuboid j |
| 141 | + dp[i] = max(dp[i], dp[j] + cuboids[i][2]); |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + // Update the overall maximum height after considering the current cuboid |
| 146 | + maxHeight = max(maxHeight, dp[i]); |
| 147 | + } |
| 148 | + |
| 149 | + return maxHeight; // Return the maximum height that can be achieved |
| 150 | + } |
| 151 | + |
| 152 | + // Function to find the maximum height of the tower that can be made from the given cuboids |
| 153 | + int maxHeight(vector<vector<int>>& cuboids) { |
| 154 | + // Sort the dimensions of each cuboid in non-decreasing order |
| 155 | + for (auto& cube : cuboids) { |
| 156 | + sort(cube.begin(), cube.end()); // Sorting each cuboid's dimensions (height, width, length) |
| 157 | + } |
| 158 | + |
| 159 | + // Sort the cuboids by their dimensions to ensure the cuboids are arranged in the right order for the DP approach |
| 160 | + sort(cuboids.begin(), cuboids.end()); // Sorting cuboids lexicographically by their dimensions |
| 161 | + |
| 162 | + return solve(cuboids, cuboids.size()); // Call the solve function to compute the maximum height |
| 163 | + } |
| 164 | +}; |
| 165 | + |
| 166 | +``` |
| 167 | +
|
| 168 | +## Problem Solution Explanation |
| 169 | +
|
| 170 | +#### 1. `int maxHeight(vector<vector<int>>& cuboids) {` |
| 171 | +This is the starting point of the `maxHeight` function, which takes a reference to a 2D vector `cuboids`. Each element of `cuboids` is a vector representing the dimensions of a cuboid, where each cuboid has three dimensions: width, length, and height. |
| 172 | +
|
| 173 | +#### 2. `for (auto& cube : cuboids) {` |
| 174 | +Here, we iterate through each cuboid in the `cuboids` list. `auto& cube` refers to each individual cuboid. This loop will allow us to sort the dimensions of each cuboid in the next step. |
| 175 | +
|
| 176 | +#### 3. `sort(cube.begin(), cube.end());` |
| 177 | +For each cuboid, we sort its dimensions in ascending order. This ensures that the width, length, and height are in non-decreasing order for each cuboid. |
| 178 | +
|
| 179 | +**Example**: |
| 180 | +Consider the cuboid `[6, 2, 5]`. After sorting, it will become `[2, 5, 6]`. This sorting is done for every cuboid in the list. |
| 181 | +
|
| 182 | +#### 4. `sort(cuboids.begin(), cuboids.end());` |
| 183 | +After sorting the dimensions of individual cuboids, we sort the cuboids themselves. This sorts the cuboids lexicographically by their dimensions. The sorting ensures that we process the cuboids in a consistent order to make the dynamic programming approach work. |
| 184 | +
|
| 185 | +**Example**: |
| 186 | +If the cuboids are `[[4, 1, 4], [6, 2, 5], [7, 3, 6]]`, after sorting each cuboid’s dimensions and sorting the cuboids, the result will be `[[1, 4, 4], [2, 5, 6], [3, 6, 7]]`. |
| 187 | +
|
| 188 | +#### 5. `return solve(cuboids, cuboids.size());` |
| 189 | +After sorting the cuboids and their dimensions, we call the `solve` function, passing the sorted `cuboids` and the total number of cuboids (`cuboids.size()`) as arguments. The `solve` function will compute and return the maximum height of the stack of cuboids. |
| 190 | +
|
| 191 | +
|
| 192 | +
|
| 193 | +### `solve` Function Explanation (Line by Line) |
| 194 | +
|
| 195 | +#### 1. `vector<int> dp(n);` |
| 196 | +Here, we declare a dynamic programming (DP) array `dp` of size `n`, where `n` is the number of cuboids. The `dp[i]` represents the maximum height of the tower that ends with the `i`-th cuboid. |
| 197 | +
|
| 198 | +#### 2. `int maxHeight = 0;` |
| 199 | +This variable will store the overall maximum height of the tower formed by stacking cuboids. |
| 200 | +
|
| 201 | +#### 3. `for (int i = 0; i < n; i++) {` |
| 202 | +This loop iterates over each cuboid `i` (from 0 to `n-1`). The idea is to consider cuboid `i` as the current cuboid that might be placed on top of previously considered cuboids. |
| 203 | +
|
| 204 | +#### 4. `dp[i] = cuboids[i][2];` |
| 205 | +We initialize `dp[i]` with the height of the `i`-th cuboid (its third dimension). This is because, at the start, the maximum height of the tower ending with cuboid `i` is just the height of cuboid `i` itself. |
| 206 | +
|
| 207 | +**Example**: |
| 208 | +If `cuboids = [[1, 4, 4], [2, 5, 6], [3, 6, 7]]`, the initial `dp` array will be `[4, 6, 7]`. |
| 209 | +
|
| 210 | +#### 5. `for (int j = 0; j < i; j++) {` |
| 211 | +The inner loop iterates over all previous cuboids (`j`), checking whether cuboid `i` can be stacked on top of cuboid `j`. |
| 212 | +
|
| 213 | +#### 6. `if (cuboids[j][0] <= cuboids[i][0] && cuboids[j][1] <= cuboids[i][1] && cuboids[j][2] <= cuboids[i][2]) {` |
| 214 | +This condition checks whether cuboid `j` can be placed under cuboid `i`. For cuboid `j` to fit under cuboid `i`, the width, length, and height of cuboid `j` must all be less than or equal to those of cuboid `i`. |
| 215 | +
|
| 216 | +**Example**: |
| 217 | +If `cuboids[i] = [3, 6, 7]` and `cuboids[j] = [2, 5, 6]`, the condition checks if `2 <= 3`, `5 <= 6`, and `6 <= 7`. Since all conditions are true, cuboid `j` can be placed under cuboid `i`. |
| 218 | +
|
| 219 | +#### 7. `dp[i] = max(dp[i], dp[j] + cuboids[i][2]);` |
| 220 | +If cuboid `j` can fit under cuboid `i`, we update the value of `dp[i]` to be the maximum of its current value and the value of `dp[j]` (the maximum height of the tower ending with cuboid `j`) plus the height of cuboid `i`. |
| 221 | +
|
| 222 | +**Example**: |
| 223 | +For `i = 2` and `j = 1`, if `dp[1] = 6` and `cuboids[2][2] = 7`, then: |
| 224 | +`dp[2] = max(7, 6 + 7) = 13`. |
| 225 | +
|
| 226 | +#### 8. `maxHeight = max(maxHeight, dp[i]);` |
| 227 | +After processing each cuboid `i`, we update `maxHeight` to be the maximum of the current `maxHeight` and `dp[i]`. This ensures that we track the overall maximum height of the tower across all cuboids. |
| 228 | +
|
| 229 | +#### 9. `return maxHeight;` |
| 230 | +After considering all cuboids, we return the `maxHeight`, which is the maximum height of the tower that can be formed by stacking cuboids. |
| 231 | +
|
| 232 | +
|
| 233 | +
|
| 234 | +### Example Walkthrough |
| 235 | +
|
| 236 | +**Input**: `cuboids = [[4, 1, 4], [6, 2, 5], [7, 3, 6]]` |
| 237 | +
|
| 238 | +1. **Step 1: Sorting Dimensions of Each Cuboid** |
| 239 | + After sorting the dimensions of each cuboid: |
| 240 | + ``` |
| 241 | + cuboids = [[1, 4, 4], [2, 5, 6], [3, 6, 7]] |
| 242 | + ``` |
| 243 | +
|
| 244 | +2. **Step 2: Sorting Cuboids Lexicographically** |
| 245 | + After sorting the cuboids lexicographically: |
| 246 | + ``` |
| 247 | + cuboids = [[1, 4, 4], [2, 5, 6], [3, 6, 7]] |
| 248 | + ``` |
| 249 | +
|
| 250 | +3. **Step 3: Initialize dp Array** |
| 251 | + Initially, the `dp` array is: |
| 252 | + ``` |
| 253 | + dp = [4, 6, 7] // Heights of individual cuboids |
| 254 | + ``` |
| 255 | +
|
| 256 | +4. **Step 4: Calculate dp Array for Maximum Heights** |
| 257 | + For each cuboid `i`, check if it can be stacked on previous cuboids `j`: |
| 258 | + - For `i = 1`, `cuboid = [2, 5, 6]`, it can be stacked on `j = 0`, so `dp[1] = max(dp[1], dp[0] + cuboids[1][2]) = max(6, 4 + 6) = 10`. |
| 259 | + - For `i = 2`, `cuboid = [3, 6, 7]`, it can be stacked on `j = 0` and `j = 1`, so `dp[2] = max(dp[2], dp[1] + cuboids[2][2]) = max(7, 10 + 7) = 17`. |
| 260 | +
|
| 261 | + After processing all cuboids, the `dp` array becomes: |
| 262 | + ``` |
| 263 | + dp = [4, 10, 17] |
| 264 | + ``` |
| 265 | +
|
| 266 | +5. **Step 5: Calculate Maximum Height** |
| 267 | + The overall maximum height is `max(4, 10, 17) = 17`. |
| 268 | +
|
| 269 | +**Output**: `17` |
| 270 | +
|
| 271 | +
|
| 272 | +
|
| 273 | +### Time Complexity: |
| 274 | +
|
| 275 | +1. **Sorting dimensions of each cuboid**: |
| 276 | + Sorting each cuboid's dimensions takes (O(3 log 3) = O(1)), so for (n) cuboids, this step takes (O(n)). |
| 277 | +
|
| 278 | +2. **Sorting the cuboids**: |
| 279 | + Sorting (n) cuboids takes (O(n log n)). |
| 280 | +
|
| 281 | +3. **Dynamic Programming with nested loops**: |
| 282 | + The outer loop runs (n) times, and the inner loop runs (i) times for each iteration of the outer loop. The time complexity of the nested loops is (O(n^2)). |
| 283 | +
|
| 284 | +Thus, the overall time complexity is: |
| 285 | +`O(n log n) + O(n^2) = O(n^2)` |
| 286 | +
|
| 287 | +### Space Complexity: |
| 288 | +
|
| 289 | +1. **Space for the DP array**: |
| 290 | + The DP array `dp` takes (O(n)) space. |
| 291 | +
|
| 292 | +2. **Space for storing the cuboids**: |
| 293 | + The cuboids themselves take (O(n)) space. |
| 294 | +
|
| 295 | +Thus, the overall space complexity is: |
| 296 | +`O(n)` |
| 297 | +
|
| 298 | +### Final Time and Space Complexity: |
| 299 | +- **Time Complexity**: (O(n^2)) |
| 300 | +- **Space Complexity**: (O(n)) |
0 commit comments