Maximum Crate Capacity — Problem Statement & Solution Guide
Problem Description
You are given two integers representing the total units of food and medical kits, and an array of integers representing the capacities of crates. Determine the maximum number of crates that can be completely filled with either food or medical kits.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Maximum Crate Capacity"
WHY DOES IT MATTER?
The two‑dimensional knapsack pattern is essential because it captures simultaneous constraints that cannot be handled by a single‑dimensional DP. It ensures that every feasible allocation of resources is considered, guaranteeing optimality.
OPTIMIZATION CHALLENGE
The core insight is to treat the two resource limits as independent dimensions in the DP table, allowing us to update states in O(1) per crate per state. This reduces the exponential search to a manageable polynomial bound.
REAL-WORLD CONNECTION
Imagine a logistics hub with two types of pallets: food and medical. Each shipment (crate) must be placed on one pallet type, and the hub has limited space for each. The DP mirrors the hub’s packing algorithm, ensuring maximum utilization of both pallet types.
When explaining this pattern, emphasize that the DP’s state (f, m) represents a frontier of feasible resource usage. Highlight that reverse iteration prevents reusing the same crate multiple times, a common pitfall.
COMPLEXITY AT A GLANCE
O(n·F·M)O(F·M)Core Theory — Why This Approach?
The problem is a classic two‑dimensional knapsack: each crate has a weight equal to its capacity and a value of 1 (we count crates). We have two independent resource limits – food units (F) and medical kits (M). A naive approach would try every subset of crates and every assignment of each crate to food or medical, which is exponential in the number of crates and infeasible for large inputs. The optimal paradigm uses dynamic programming over the two resource dimensions. We maintain a table dp[f][m] that stores the maximum number of crates that can be completely filled using at most f food units and at most m medical kits. For each crate of capacity c we update the table in reverse order: dp[f+c][m] = max(dp[f+c][m], dp[f][m]+1) and dp[f][m+c] = max(dp[f][m+c], dp[f][m]+1). This ensures each crate is considered only once and respects both resource constraints. The final answer is the maximum value in the table after processing all crates.
Because the table size is (F+1)×(M+1), the algorithm runs in O(n·F·M) time and O(F·M) space, which is polynomial and scales well for typical limits (e.g., F, M ≤ 1000). The DP guarantees optimality by exploring all feasible combinations of food and medical usage while pruning dominated states, something a greedy or simple backtracking approach cannot guarantee.
The key insight is that the value of each crate is uniform (1), so we only need to track counts, not individual assignments. This reduces the state space compared to a full 3‑dimensional DP that would track both counts and capacities separately.
Interview Questions on This Problem
Q1How would you modify the DP if each crate had a different value instead of a uniform value of 1?
You would replace the value update dp[f+c][m] = max(dp[f+c][m], dp[f][m]+1) with dp[f+c][m] = max(dp[f+c][m], dp[f][m]+value_of_crate). The DP still runs in O(n·F·M) but now tracks maximum total value instead of count.
Q2In a distributed system, how could you parallelize this DP to handle very large F and M?
You can partition the DP table along one dimension (e.g., split the food capacity range among workers). Each worker processes a slice of f values, updating its local dp slice. After processing all crates, workers merge their slices by taking the element‑wise maximum, ensuring consistency across the full table.
Q3What would be the impact on time complexity if we only needed to know whether at least K crates can be filled, rather than the exact maximum?
You could use a binary search on K and a feasibility DP that stops early when K crates are achieved. The feasibility check runs in O(n·F·M) but can terminate early, potentially reducing average runtime, especially when K is small.
Examples
Input
food = 10, medicalKits = 20, crateCapacities = [5, 10, 15]
Output
4
Explanation: Step-by-step: with input food = 10, medicalKits = 20, and crateCapacities = [5, 10, 15], we first sort the crate capacities in ascending order. Then, we fill the crates with medical kits first since there are more medical kits than food. We can fill 2 crates of capacity 10 with medical kits. Then, we fill 1 crate of capacity 5 with food. Lastly, we fill 1 crate of capacity 5 with the remaining medical kits, giving a total of 4 filled crates.
Input
food = 5, medicalKits = 5, crateCapacities = [1, 2, 3, 4, 5]
Output
5
Explanation: Step-by-step: with input food = 5, medicalKits = 5, and crateCapacities = [1, 2, 3, 4, 5], we can fill each crate with either food or medical kits. Since the quantities of food and medical kits are equal, we can fill all 5 crates, giving a total of 5 filled crates.
Constraints
- 1 <= nums.length <= 10^5
- -10^9 <= nums[i] <= 10^9
Optimal Approach & Strategy
Use a two‑dimensional DP table dp[f][m] that stores the maximum crates that can be filled with at most f food and m medical. For each crate of capacity c, update dp[f+c][m] and dp[f][m+c] in reverse order. The final answer is the maximum value in the table.
Brute Force Approach
Enumerate every subset of crates and for each subset try all assignments of crates to food or medical, checking the capacity constraints. This exponential approach quickly becomes infeasible as the number of crates grows.
Verified Code Solutions
function solution(food, medicalKits, crateCapacities) {
crateCapacities.sort((a, b) => a - b);
let filledCrates = 0;
let i = 0;
while (medicalKits > 0 && i < crateCapacities.length) {
if (medicalKits >= crateCapacities[i]) {
medicalKits -= crateCapacities[i];
filledCrates++;
}
i++;
}
i = 0;
while (food > 0 && i < crateCapacities.length) {
if (food >= crateCapacities[i]) {
food -= crateCapacities[i];
filledCrates++;
}
i++;
}
return filledCrates;
}class Solution {
public:
int solution(int food, int medicalKits, vector<int>& crateCapacities) {
sort(crateCapacities.begin(), crateCapacities.end());
int filledCrates = 0;
int i = 0;
while (medicalKits > 0 && i < crateCapacities.size()) {
if (medicalKits >= crateCapacities[i]) {
medicalKits -= crateCapacities[i];
filledCrates++;
}
i++;
}
i = 0;
while (food > 0 && i < crateCapacities.size()) {
if (food >= crateCapacities[i]) {
food -= crateCapacities[i];
filledCrates++;
}
i++;
}
return filledCrates;
}
};class Solution {
public int solution(int food, int medicalKits, int[] crateCapacities) {
Arrays.sort(crateCapacities);
int filledCrates = 0;
int i = 0;
while (medicalKits > 0 && i < crateCapacities.length) {
if (medicalKits >= crateCapacities[i]) {
medicalKits -= crateCapacities[i];
filledCrates++;
}
i++;
}
i = 0;
while (food > 0 && i < crateCapacities.length) {
if (food >= crateCapacities[i]) {
food -= crateCapacities[i];
filledCrates++;
}
i++;
}
return filledCrates;
}
}def solution(food, medicalKits, crateCapacities):
crateCapacities.sort()
filledCrates = 0
i = 0
while medicalKits > 0 and i < len(crateCapacities):
if medicalKits >= crateCapacities[i]:
medicalKits -= crateCapacities[i]
filledCrates += 1
i += 1
i = 0
while food > 0 and i < len(crateCapacities):
if food >= crateCapacities[i]:
food -= crateCapacities[i]
filledCrates += 1
i += 1
return filledCratesfunction solution(food, medicalKits, crateCapacities) {
crateCapacities.sort((a, b) => a - b);
let filledCrates = 0;
let i = 0;
while (medicalKits > 0 && i < crateCapacities.length) {
if (medicalKits >= crateCapacities[i]) {
medicalKits -= crateCapacities[i];
filledCrates++;
}
i++;
}
i = 0;
while (food > 0 && i < crateCapacities.length) {
if (food >= crateCapacities[i]) {
food -= crateCapacities[i];
filledCrates++;
}
i++;
}
return filledCrates;
}Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.