The Leetcode problem Put Boxes Into the Warehouse II presents you with two arrays:
boxes
: an array where boxes[i]
is the height of the ith box.warehouse
: an array where warehouse[j]
is the height of the jth room in the warehouse, arranged from left to right.j
, it must be pushed in from the leftmost end (position 0) and pass through all rooms 0
to j-1
. If a box is too tall for any room it passes through, it cannot be placed in room j
.
At first glance, it might seem reasonable to try every possible arrangement of boxes and rooms, but this is not efficient.
The main challenge is that a box, to reach a certain room, must fit through all rooms before it.
This means the effective height of each room is the minimum height encountered from the left up to that room.
A naive approach would be to try to fit every box into every room, but that quickly becomes too slow as the input size grows.
Instead, we realize that sorting both the boxes and the warehouse (after adjusting for bottleneck heights) allows us to use a greedy approach,
always fitting the smallest available box into the smallest available room it can fit into.
This way, we maximize the number of boxes placed and don't "waste" tall rooms on small boxes.
Let's break down the steps for an efficient solution:
boxes
in ascending order so we can easily pick the smallest available box.
Input:
boxes = [4,3,4,1]
warehouse = [5,3,3,4,1]
Step 1: Preprocess warehouse
- Start from the left, update each warehouse room to be the minimum so far:
- warehouse: [5,3,3,3,1] (since 5, min(5,3)=3, min(3,3)=3, min(3,4)=3, min(3,1)=1)
Step 2: Sort
- boxes: [1,3,4,4]
- warehouse: [1,3,3,3,5] (after sorting)
Step 3: Greedy Placement
- Try box 1 in room 1: fits (count=1)
- Try box 3 in room 3: fits (count=2)
- Try box 4 in room 3: doesn't fit, try next room (room 3): doesn't fit, try next room (room 5): fits (count=3)
Result: Maximum 3 boxes can be placed.
Brute-force approach:
This problem is a great example of how preprocessing and greedy strategies can turn an otherwise intractable brute-force search into an efficient solution. By reducing each warehouse room to its true accessible height and sorting both boxes and rooms, we can match the smallest boxes to the smallest rooms. The key insight is to recognize how bottlenecks in the warehouse affect box placement and to always use the smallest box that fits each time. This approach is both elegant and fast, making it ideal for real-world scenarios where maximizing utilization is important.
class Solution:
def maxBoxesInWarehouse(self, boxes, warehouse):
# Step 1: Preprocess the warehouse to minimum heights up to each room
min_height = float('inf')
for i in range(len(warehouse)):
min_height = min(min_height, warehouse[i])
warehouse[i] = min_height
# Step 2: Sort boxes and warehouse
boxes.sort()
sorted_warehouse = sorted(warehouse)
# Step 3: Greedy two-pointer placement
res = 0
i = 0 # pointer for boxes
j = 0 # pointer for warehouse
while i < len(boxes) and j < len(sorted_warehouse):
if boxes[i] <= sorted_warehouse[j]:
res += 1
i += 1
j += 1
else:
j += 1
return res
class Solution {
public:
int maxBoxesInWarehouse(vector<int>& boxes, vector<int>& warehouse) {
// Step 1: Preprocess warehouse to minimum heights
int min_height = INT_MAX;
for (int i = 0; i < warehouse.size(); ++i) {
min_height = min(min_height, warehouse[i]);
warehouse[i] = min_height;
}
// Step 2: Sort boxes and warehouse
sort(boxes.begin(), boxes.end());
vector<int> sorted_warehouse = warehouse;
sort(sorted_warehouse.begin(), sorted_warehouse.end());
// Step 3: Greedy placement
int res = 0, i = 0, j = 0;
while (i < boxes.size() && j < sorted_warehouse.size()) {
if (boxes[i] <= sorted_warehouse[j]) {
++res;
++i;
++j;
} else {
++j;
}
}
return res;
}
};
class Solution {
public int maxBoxesInWarehouse(int[] boxes, int[] warehouse) {
// Step 1: Preprocess warehouse to minimum heights
int minHeight = Integer.MAX_VALUE;
for (int i = 0; i < warehouse.length; ++i) {
minHeight = Math.min(minHeight, warehouse[i]);
warehouse[i] = minHeight;
}
// Step 2: Sort boxes and warehouse
Arrays.sort(boxes);
int[] sortedWarehouse = warehouse.clone();
Arrays.sort(sortedWarehouse);
// Step 3: Greedy placement
int res = 0, i = 0, j = 0;
while (i < boxes.length && j < sortedWarehouse.length) {
if (boxes[i] <= sortedWarehouse[j]) {
res++;
i++;
j++;
} else {
j++;
}
}
return res;
}
}
var maxBoxesInWarehouse = function(boxes, warehouse) {
// Step 1: Preprocess warehouse to minimum heights
let minHeight = Infinity;
for (let i = 0; i < warehouse.length; ++i) {
minHeight = Math.min(minHeight, warehouse[i]);
warehouse[i] = minHeight;
}
// Step 2: Sort boxes and warehouse
boxes.sort((a, b) => a - b);
let sortedWarehouse = warehouse.slice().sort((a, b) => a - b);
// Step 3: Greedy placement
let res = 0, i = 0, j = 0;
while (i < boxes.length && j < sortedWarehouse.length) {
if (boxes[i] <= sortedWarehouse[j]) {
res++;
i++;
j++;
} else {
j++;
}
}
return res;
};