1564. Put Boxes Into the Warehouse I π
Problem Description
You have a warehouse with n
rooms arranged in a line from left to right, where each room has a specific height given by the array warehouse
. You also have multiple boxes with heights given by the array boxes
.
The goal is to push as many boxes as possible into the warehouse following these rules:
-
No stacking: Boxes cannot be placed on top of each other - each box occupies one room.
-
Flexible ordering: You can rearrange the boxes in any order before pushing them into the warehouse.
-
Left-to-right only: Boxes must be pushed into the warehouse from the left side and move towards the right.
-
Height constraint: When pushing a box through the warehouse, if it encounters a room with height less than the box's height, the box gets stuck at the room just before it. This also blocks all subsequent boxes from going past this point.
For example, if warehouse = [4, 3, 5, 2, 6]
and you push a box of height 4
, it can pass through rooms 0 and 1 (heights 4 and 3) but gets stuck before room 3 (height 2), so it ends up in room 2. No other boxes can now be placed beyond room 2.
The solution uses a preprocessing step to find the effective height limit for each room (the minimum height from the entrance to that room), then greedily matches the smallest available boxes to the rightmost available positions in the warehouse. This maximizes the number of boxes that can fit.
Return the maximum number of boxes that can be placed in the warehouse.
Intuition
The key insight is recognizing that a box's journey through the warehouse is limited by the shortest room it encounters along its path. If a box needs to reach room i
, it must pass through all rooms from 0
to i-1
first. Therefore, the effective height constraint for placing a box in room i
is not just warehouse[i]
, but the minimum height among all rooms from 0
to i
.
This leads us to precompute the "effective height" for each room position. For room i
, we calculate left[i] = min(warehouse[0], warehouse[1], ..., warehouse[i])
. This represents the maximum height a box can have if we want to place it in room i
.
Once we have these effective heights, we need to maximize the number of boxes we can place. Here's where the greedy strategy comes in:
-
Sort boxes in ascending order: We want to use smaller boxes first because they have fewer restrictions and can fit in more places.
-
Fill from right to left: We start placing boxes from the rightmost available position. Why? Because if we can fit a box at position
j
, we could also fit it at any positionk < j
(sinceleft[k] >= left[j]
). By placing it as far right as possible, we leave more room on the left for other boxes. -
Match smallest box to rightmost position: For each box (starting from smallest), we find the rightmost room where it can fit. If a box can't fit in the current rightmost available position, we skip that position and try positions further left until we find one that works.
This greedy approach ensures we accommodate as many boxes as possible by always making the locally optimal choice of using the smallest available box for the rightmost available position.
Solution Approach
The implementation follows a two-phase approach: preprocessing and greedy matching.
Phase 1: Preprocessing the Warehouse
First, we compute the effective height constraints for each room:
left = [warehouse[0]] * n
for i in range(1, n):
left[i] = min(left[i - 1], warehouse[i])
- Initialize
left
array with the first room's height - For each subsequent room
i
, calculateleft[i] = min(left[i-1], warehouse[i])
- This gives us the minimum height from room 0 to room
i
, representing the tallest box that can reach roomi
For example, if warehouse = [4, 3, 5, 2, 6]
, then left = [4, 3, 3, 2, 2]
.
Phase 2: Greedy Box Placement
Next, we sort the boxes and match them with warehouse positions:
boxes.sort() i, j = 0, n - 1
- Sort boxes in ascending order to prioritize smaller boxes
- Use two pointers:
i
for boxes (starting from smallest) andj
for warehouse positions (starting from rightmost)
The matching loop:
while i < len(boxes):
while j >= 0 and left[j] < boxes[i]:
j -= 1
if j < 0:
break
i, j = i + 1, j - 1
- For each box
boxes[i]
, find the rightmost available position where it fits - If
left[j] < boxes[i]
, the box is too tall for positionj
, so movej
left - Once we find a valid position (or run out of positions), either:
- Place the box at position
j
and move to next box (i + 1
) and next available position (j - 1
) - Or break if no positions remain (
j < 0
)
- Place the box at position
The final answer is i
, which represents the number of boxes successfully placed.
Time Complexity: O(n + m log m)
where n
is warehouse length and m
is number of boxes
Space Complexity: O(n)
for the left
array
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example with warehouse = [4, 3, 5, 2, 6]
and boxes = [3, 5, 5, 2]
.
Step 1: Preprocess the warehouse
We calculate the effective height constraint for each room by finding the minimum height from the entrance to that room:
- Room 0:
left[0] = 4
(only room 0 with height 4) - Room 1:
left[1] = min(4, 3) = 3
(minimum of rooms 0-1) - Room 2:
left[2] = min(3, 5) = 3
(minimum of rooms 0-2) - Room 3:
left[3] = min(3, 2) = 2
(minimum of rooms 0-3) - Room 4:
left[4] = min(2, 6) = 2
(minimum of rooms 0-4)
So left = [4, 3, 3, 2, 2]
. This tells us:
- A box needs height β€ 4 to reach room 0
- A box needs height β€ 3 to reach room 1
- A box needs height β€ 3 to reach room 2
- A box needs height β€ 2 to reach rooms 3 or 4
Step 2: Sort the boxes
Sort boxes = [3, 5, 5, 2]
β [2, 3, 5, 5]
Step 3: Greedy matching
Start with i = 0
(smallest box) and j = 4
(rightmost room):
-
Box 0 (height 2): Check room 4 where
left[4] = 2
. Since2 β€ 2
, box fits! Place it in room 4. Update:i = 1, j = 3
-
Box 1 (height 3): Check room 3 where
left[3] = 2
. Since3 > 2
, box doesn't fit. Move left to room 2 whereleft[2] = 3
. Since3 β€ 3
, box fits! Place it in room 2. Update:i = 2, j = 1
-
Box 2 (height 5): Check room 1 where
left[1] = 3
. Since5 > 3
, box doesn't fit. Move left to room 0 whereleft[0] = 4
. Since5 > 4
, still doesn't fit. We've run out of rooms (j = -1
), so this box cannot be placed. -
Box 3 (height 5): Since
j < 0
, no rooms are available. This box cannot be placed.
Result: We successfully placed 2 boxes (the boxes with heights 2 and 3).
The final warehouse configuration would have:
- Room 2: Box of height 3
- Room 4: Box of height 2
- Other rooms: Empty
This demonstrates how the algorithm prioritizes smaller boxes and places them as far right as possible to maximize the total number of boxes that can fit.
Solution Implementation
1class Solution:
2 def maxBoxesInWarehouse(self, boxes: List[int], warehouse: List[int]) -> int:
3 # Get the warehouse length
4 warehouse_length = len(warehouse)
5
6 # Create an array to store the effective height limit at each position
7 # The effective height at position i is the minimum height from entrance to position i
8 effective_heights = [warehouse[0]] * warehouse_length
9
10 # Calculate effective heights for each warehouse position
11 # Each position's effective height is limited by the minimum height encountered so far
12 for i in range(1, warehouse_length):
13 effective_heights[i] = min(effective_heights[i - 1], warehouse[i])
14
15 # Sort boxes in ascending order to try placing smaller boxes first
16 boxes.sort()
17
18 # Initialize pointers: box_index for boxes, warehouse_pos for warehouse positions
19 box_index = 0
20 warehouse_pos = warehouse_length - 1
21
22 # Try to place each box starting from the smallest
23 while box_index < len(boxes):
24 # Find the rightmost warehouse position that can accommodate current box
25 # Move warehouse pointer left until we find a suitable position
26 while warehouse_pos >= 0 and effective_heights[warehouse_pos] < boxes[box_index]:
27 warehouse_pos -= 1
28
29 # If no suitable position found, we can't place any more boxes
30 if warehouse_pos < 0:
31 break
32
33 # Place the box and move to next box and next available warehouse position
34 box_index += 1
35 warehouse_pos -= 1
36
37 # Return the number of boxes successfully placed
38 return box_index
39
1class Solution {
2 public int maxBoxesInWarehouse(int[] boxes, int[] warehouse) {
3 int warehouseLength = warehouse.length;
4
5 // Create an array to store the maximum height constraint from entrance to each position
6 // left[i] represents the minimum height from warehouse[0] to warehouse[i]
7 int[] maxHeightFromEntrance = new int[warehouseLength];
8 maxHeightFromEntrance[0] = warehouse[0];
9
10 // Calculate the effective height limit for each warehouse position
11 // A box must pass through all previous positions to reach position i
12 for (int i = 1; i < warehouseLength; i++) {
13 maxHeightFromEntrance[i] = Math.min(maxHeightFromEntrance[i - 1], warehouse[i]);
14 }
15
16 // Sort boxes in ascending order to try placing smaller boxes first
17 Arrays.sort(boxes);
18
19 // Two pointers: boxIndex for current box, warehouseIndex for current warehouse position
20 int boxIndex = 0;
21 int warehouseIndex = warehouseLength - 1;
22
23 // Try to place each box starting from the smallest
24 while (boxIndex < boxes.length) {
25 // Find the rightmost warehouse position that can accommodate current box
26 while (warehouseIndex >= 0 && maxHeightFromEntrance[warehouseIndex] < boxes[boxIndex]) {
27 warehouseIndex--;
28 }
29
30 // No more warehouse positions available for remaining boxes
31 if (warehouseIndex < 0) {
32 break;
33 }
34
35 // Place current box and move to next box and previous warehouse position
36 boxIndex++;
37 warehouseIndex--;
38 }
39
40 // Return the number of boxes successfully placed
41 return boxIndex;
42 }
43}
44
1class Solution {
2public:
3 int maxBoxesInWarehouse(vector<int>& boxes, vector<int>& warehouse) {
4 int warehouseSize = warehouse.size();
5
6 // Create an array to store the minimum height from entrance to each position
7 // leftMinHeight[i] represents the minimum height from position 0 to position i
8 int leftMinHeight[warehouseSize];
9
10 // Initialize the first position with the first warehouse height
11 leftMinHeight[0] = warehouse[0];
12
13 // Calculate minimum heights from entrance to each position
14 // Any box must fit through all previous positions to reach position i
15 for (int i = 1; i < warehouseSize; ++i) {
16 leftMinHeight[i] = min(leftMinHeight[i - 1], warehouse[i]);
17 }
18
19 // Sort boxes in ascending order to try placing smaller boxes first
20 sort(boxes.begin(), boxes.end());
21
22 // Use two pointers: boxIndex for boxes, warehousePos for warehouse positions
23 int boxIndex = 0;
24 int warehousePos = warehouseSize - 1;
25
26 // Try to place each box starting from the smallest
27 while (boxIndex < boxes.size()) {
28 // Find the rightmost position where current box can fit
29 // Move left until we find a position with sufficient height
30 while (warehousePos >= 0 && leftMinHeight[warehousePos] < boxes[boxIndex]) {
31 --warehousePos;
32 }
33
34 // If no valid position found, we cannot place any more boxes
35 if (warehousePos < 0) {
36 break;
37 }
38
39 // Place the box at the current position
40 ++boxIndex;
41 // Move to the next available position (positions are used from right to left)
42 --warehousePos;
43 }
44
45 // Return the number of boxes successfully placed
46 return boxIndex;
47 }
48};
49
1/**
2 * Determines the maximum number of boxes that can be placed in a warehouse.
3 * Each box must fit through all warehouse positions from entrance to its placement position.
4 *
5 * @param boxes - Array of box heights
6 * @param warehouse - Array of warehouse ceiling heights at each position
7 * @returns Maximum number of boxes that can be placed in the warehouse
8 */
9function maxBoxesInWarehouse(boxes: number[], warehouse: number[]): number {
10 const warehouseLength: number = warehouse.length;
11
12 // Create array to store minimum height from entrance to each position
13 // left[i] represents the minimum ceiling height from position 0 to position i
14 const minHeightFromEntrance: number[] = new Array(warehouseLength);
15
16 // Initialize first position with its ceiling height
17 minHeightFromEntrance[0] = warehouse[0];
18
19 // Calculate minimum heights for each position from the entrance
20 for (let position = 1; position < warehouseLength; position++) {
21 minHeightFromEntrance[position] = Math.min(
22 minHeightFromEntrance[position - 1],
23 warehouse[position]
24 );
25 }
26
27 // Sort boxes in ascending order by height
28 boxes.sort((boxA, boxB) => boxA - boxB);
29
30 // Two pointers: boxIndex for current box, warehousePosition for current warehouse position
31 let boxIndex: number = 0;
32 let warehousePosition: number = warehouseLength - 1;
33
34 // Try to place boxes starting from smallest box and furthest warehouse position
35 while (boxIndex < boxes.length) {
36 // Find the furthest valid position for current box
37 while (warehousePosition >= 0 && minHeightFromEntrance[warehousePosition] < boxes[boxIndex]) {
38 warehousePosition--;
39 }
40
41 // No valid position found for current box
42 if (warehousePosition < 0) {
43 break;
44 }
45
46 // Place the box and move to next box and previous warehouse position
47 boxIndex++;
48 warehousePosition--;
49 }
50
51 // Return the number of boxes successfully placed
52 return boxIndex;
53}
54
Time and Space Complexity
Time Complexity: O(n + m log m)
where n
is the length of the warehouse array and m
is the length of the boxes array.
- Creating the
left
array requires a single pass through the warehouse array:O(n)
- Sorting the boxes array:
O(m log m)
- The while loops for matching boxes to warehouse positions:
O(n + m)
- The outer loop runs at most
m
times (for each box) - The inner loop decrements
j
fromn-1
to potentially-1
, but each position is visited at most once across all iterations - Combined, both loops together process at most
O(n + m)
operations
- The outer loop runs at most
Overall: O(n) + O(m log m) + O(n + m) = O(n + m log m)
Space Complexity: O(n)
- The
left
array storesn
elements:O(n)
- The sorting operation on boxes (if using in-place sorting like Timsort in Python):
O(1)
toO(m)
auxiliary space in worst case, but typicallyO(log m)
- Other variables (
i
,j
):O(1)
The dominant space usage is the left
array, giving us O(n)
space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Misunderstanding the Height Constraint Logic
The Problem: A common mistake is thinking that a box can only fit in a room if the box height is less than or equal to that specific room's height, rather than considering all rooms the box must pass through to reach that position.
Incorrect Approach:
# Wrong: Only checking individual room heights
for box in sorted(boxes):
for i in range(len(warehouse)):
if warehouse[i] >= box: # This is wrong!
# Place box at position i
break
Why It's Wrong:
If warehouse = [4, 3, 5, 2, 6]
and we have a box of height 5, the incorrect logic would try to place it at position 2 (height 5). However, the box cannot reach position 2 because it gets stuck at position 1 (height 3).
The Solution:
Always use the preprocessed effective_heights
array that tracks the minimum height from the entrance to each position:
# Correct: Using effective heights
effective_heights = [warehouse[0]] * n
for i in range(1, n):
effective_heights[i] = min(effective_heights[i - 1], warehouse[i])
Pitfall 2: Not Starting from the Rightmost Position
The Problem: Another mistake is placing boxes from left to right instead of trying to place them as far right as possible.
Incorrect Approach:
# Wrong: Starting from the left
j = 0 # Starting from leftmost position
for box in sorted(boxes):
while j < n and effective_heights[j] < box:
j += 1
if j < n:
j += 1 # Move to next position
Why It's Wrong:
This approach fills the warehouse from left to right, which can block smaller boxes from reaching deeper positions. For example, with warehouse = [5, 4, 3, 2, 1]
and boxes = [1, 2, 3]
, placing box 1 at position 0 wastes space that could be used for larger boxes.
The Solution: Always start searching from the rightmost position to maximize space utilization:
# Correct: Starting from the right warehouse_pos = warehouse_length - 1 while warehouse_pos >= 0 and effective_heights[warehouse_pos] < boxes[box_index]: warehouse_pos -= 1
Pitfall 3: Forgetting to Sort the Boxes
The Problem: Processing boxes in their original order instead of sorting them first.
Incorrect Approach:
# Wrong: Not sorting boxes for box in boxes: # Using original order # Try to place box
Why It's Wrong:
Without sorting, larger boxes might be placed first and block positions that smaller boxes could have used. For instance, with boxes = [5, 1, 2]
and warehouse = [6, 3, 4]
, placing the box of height 5 first would block all other boxes, resulting in only 1 box placed instead of the optimal 2.
The Solution: Always sort boxes in ascending order before placement:
# Correct: Sort boxes first boxes.sort()
This ensures smaller boxes are placed first, leaving more room for additional boxes and maximizing the total count.
Which data structure is used to implement recursion?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Donβt Miss This!