Minimum Space Wasted From Packaging
HardPrompt
You have n packages that you are trying to place in boxes, one package in each box. There are m suppliers that each produce boxes of different sizes (with infinite supply). A package can be placed in a box if the size of the package is less than or equal to the size of the box.
The package sizes are given as an integer array packages, where packages[i] is the size of the ith package. The suppliers are given as a 2D integer array boxes, where boxes[j] is an array of box sizes that the jth supplier produces.
You want to choose a single supplier and use boxes from them such that the total wasted space is minimized. For each package in a box, we define the space wasted to be size of the box - size of the package. The total wasted space is the sum of the space wasted in all the boxes.
- For example, if you have to fit packages with sizes
[2,3,5]and the supplier offers boxes of sizes[4,8], you can fit the packages of size-2and size-3into two boxes of size-4and the package with size-5into a box of size-8. This would result in a waste of(4-2) + (4-3) + (8-5) = 6.
Return the minimum total wasted space by choosing the box supplier optimally, or -1 if it is impossible to fit all the packages inside boxes. Since the answer may be large, return it modulo 109 + 7.
Example 1:
Input: packages = [2,3,5], boxes = [[4,8],[2,8]]
Output: 6
Explanation: It is optimal to choose the first supplier, using two size-4 boxes and one size-8 box.
The total waste is (4-2) + (4-3) + (8-5) = 6.Example 2:
Input: packages = [2,3,5], boxes = [[1,4],[2,3],[3,4]]
Output: -1
Explanation: There is no box that the package of size 5 can fit in.Example 3:
Input: packages = [3,5,8,10,11,12], boxes = [[12],[11,9],[10,5,14]]
Output: 9
Explanation: It is optimal to choose the third supplier, using two size-5 boxes, two size-10 boxes, and two size-14 boxes.
The total waste is (5-3) + (5-5) + (10-8) + (10-10) + (14-11) + (14-12) = 9.
Constraints:
n == packages.lengthm == boxes.length1 <= n <= 1051 <= m <= 1051 <= packages[i] <= 1051 <= boxes[j].length <= 1051 <= boxes[j][k] <= 105sum(boxes[j].length) <= 105- The elements in
boxes[j]are distinct.
Approaches
2 approaches with complexity analysis and trade-offs.
A relatively straightforward approach is to consider each supplier one by one. For a given supplier, we need to calculate the total wasted space if we use their boxes. To minimize waste for a single package, we must choose the smallest box from the supplier that is large enough to hold the package.
Algorithm
- Find the maximum package size.
- Initialize
min_wasteto a very large value (infinity). - For each supplier
s:- Sort the boxes of supplier
s. - If the largest box from
sis smaller than the maximum package size, this supplier is invalid, so we continue to the next one. - Initialize
current_wasteto 0. - For each package
p:- Use binary search on the sorted boxes of
sto find the smallest boxbwhereb >= p. - Add the waste
b - ptocurrent_waste.
- Use binary search on the sorted boxes of
- After iterating through all packages, update
min_waste = min(min_waste, current_waste).
- Sort the boxes of supplier
- If
min_wasteis still infinity, it means no supplier could fit all packages, so return -1. Otherwise, returnmin_wastemodulo 10^9 + 7.
Walkthrough
To find this "best-fit" box efficiently, we can first sort the box sizes offered by the supplier. Then, for each package, we can use binary search on the sorted box sizes to find the smallest box that is greater than or equal to the package size. We calculate the waste for this package (box_size - package_size) and add it to a running total for the current supplier. After doing this for all packages, we get the total waste for one supplier. We repeat this process for every supplier and keep track of the minimum total waste found. An initial check can be performed: if a supplier's largest box is smaller than the largest package, that supplier cannot be used.
class Solution { public int minWastedSpace(int[] packages, int[][] boxes) { long minTotalWaste = Long.MAX_VALUE; int n = packages.length; Arrays.sort(packages); int maxPackage = packages[n - 1]; for (int[] supplierBoxes : boxes) { Arrays.sort(supplierBoxes); int m = supplierBoxes.length; if (supplierBoxes[m - 1] < maxPackage) { continue; // This supplier cannot handle the largest package } long currentWaste = 0; for (int p : packages) { // Binary search to find the smallest box >= p (lower_bound) int low = 0, high = m - 1; int bestBoxIndex = -1; while (low <= high) { int mid = low + (high - low) / 2; if (supplierBoxes[mid] >= p) { bestBoxIndex = mid; high = mid - 1; } else { low = mid + 1; } } currentWaste += (long)supplierBoxes[bestBoxIndex] - p; } minTotalWaste = Math.min(minTotalWaste, currentWaste); } if (minTotalWaste == Long.MAX_VALUE) { return -1; } return (int) (minTotalWaste % 1_000_000_007); }}Complexity
Time
O(N log N + sum(k_j log k_j + N log k_j)) for j from 0 to M-1. Here, N is the number of packages, M is the number of suppliers, and k_j is the number of box types for supplier j. The `N * log(k_j)` term inside the sum makes this approach too slow for the given constraints, as it could lead to O(M * N * log K) in the worst case.
Space
O(K) or O(log K) for sorting, depending on the implementation, where K is the maximum number of box types for a single supplier.
Trade-offs
Pros
Conceptually simpler than the optimal approach.
Cons
Inefficient due to its time complexity.
The nested loop structure, iterating through each package for each supplier, leads to a Time Limit Exceeded error on large inputs.
The previous approach is inefficient because it re-evaluates each package for every supplier. A much faster way is to process packages in batches. If we sort both the packages and the boxes for a given supplier, we can calculate the total waste in a single pass over the boxes.
Algorithm
- Sort the
packagesarray. - Compute a prefix sum array for the sorted
packagesto quickly find the sum of sizes of a range of packages. - Initialize
min_wasteto a very large value (infinity). - For each supplier:
- Sort their box sizes.
- If their largest box is smaller than the largest package, skip this supplier.
- Initialize
current_waste = 0andlast_package_idx = 0(to track which packages have been assigned a box). - For each
box_sizein the sorted list of boxes:- Use binary search on
packagesto find the indexiof the first package that is larger than the currentbox_size. The search is performed on the yet-unassigned packages. - The packages from
last_package_idxtoi-1will be placed in boxes of this size. - Calculate the waste for this group of packages:
(i - last_package_idx) * box_size - (sum of package sizes from last_package_idx to i-1). The sum is found in O(1) using the prefix sum array. - Add this group's waste to
current_waste. - Update
last_package_idx = i. - If all packages are assigned (
last_package_idx == n), we can stop processing boxes for this supplier.
- Use binary search on
- Update
min_wastewithcurrent_wasteif it's smaller.
- If
min_wastewas never updated, return -1. Otherwise, returnmin_wastemodulo 10^9 + 7.
Walkthrough
The core idea is to first sort the packages array once. This allows us to group packages by size. We also pre-compute the prefix sums of the package sizes, which will allow us to find the sum of sizes of any contiguous sub-array of packages in O(1) time. Then, for each supplier, we sort their box sizes. We iterate through the sorted box sizes. For a box of size b, we determine which packages will be placed in it. These are the packages that are too large for any smaller box from this supplier but small enough to fit in a box of size b. Since both packages and boxes are sorted, we can use binary search (upper_bound) on the packages array to find how many packages can fit into the current box size b. Let's say we find that packages up to index i can fit. If packages up to index j fit in the previously considered smaller box, then packages from index j to i-1 will be placed in boxes of size b. The waste for this group of packages is (number of packages) * b - (sum of their sizes). The number of packages is i - j, and the sum of their sizes can be found in O(1) using our pre-computed prefix sums. We sum up the waste for all such groups to get the total waste for the supplier and take the minimum over all suppliers.
class Solution { public int minWastedSpace(int[] packages, int[][] boxes) { int n = packages.length; long MOD = 1_000_000_007; Arrays.sort(packages); long[] prefixSum = new long[n + 1]; for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + packages[i]; } long minTotalWaste = Long.MAX_VALUE; for (int[] supplierBoxes : boxes) { Arrays.sort(supplierBoxes); int m = supplierBoxes.length; if (supplierBoxes[m - 1] < packages[n - 1]) { continue; } long currentWaste = 0; int lastPackageIndex = 0; for (int boxSize : supplierBoxes) { if (lastPackageIndex == n) { break; } // Find the index of the first package > boxSize (upper_bound) // in the range [lastPackageIndex, n). int lo = lastPackageIndex; int hi = n; while (lo < hi) { int mid = lo + (hi - lo) / 2; if (packages[mid] <= boxSize) { lo = mid + 1; } else { hi = mid; } } int currentPackageIndex = lo; if (currentPackageIndex > lastPackageIndex) { long numPackages = currentPackageIndex - lastPackageIndex; long packageSumForGroup = prefixSum[currentPackageIndex] - prefixSum[lastPackageIndex]; currentWaste += (numPackages * boxSize) - packageSumForGroup; } lastPackageIndex = currentPackageIndex; } minTotalWaste = Math.min(minTotalWaste, currentWaste); } if (minTotalWaste == Long.MAX_VALUE) { return -1; } return (int) (minTotalWaste % MOD); }}Complexity
Time
O(N log N + S * log K + S * log N), where N is the number of packages, S is the total number of box types across all suppliers (`sum(boxes[j].length)`), and K is the maximum number of box types for a single supplier. This is efficient enough to pass the given constraints.
Space
O(N) to store the prefix sums of package sizes.
Trade-offs
Pros
Highly efficient and optimal for the given constraints.
Avoids redundant computations by processing packages in groups, leading to a significantly better time complexity.
Cons
Slightly more complex to implement due to the use of prefix sums and a more involved binary search logic for grouping packages.
Solutions
Solution
class Solution { public int minWastedSpace ( int [] packages , int [][] boxes ) { int n = packages . length ; final long inf = 1L << 62 ; Arrays . sort ( packages ); long ans = inf ; for ( var box : boxes ) { Arrays . sort ( box ); if ( packages [ n - 1 ] > box [ box . length - 1 ]) { continue ; } long s = 0 ; int i = 0 ; for ( int b : box ) { int j = search ( packages , b , i ); s += 1L * ( j - i ) * b ; i = j ; } ans = Math . min ( ans , s ); } if ( ans == inf ) { return - 1 ; } long s = 0 ; for ( int p : packages ) { s += p ; } final int mod = ( int ) 1 e9 + 7 ; return ( int ) (( ans - s ) % mod ); } private int search ( int [] nums , int x , int l ) { int r = nums . length ; while ( l < r ) { int mid = ( l + r ) >> 1 ; if ( nums [ mid ] > x ) { r = mid ; } else { l = mid + 1 ; } } return l ; } }class Solution { public: int minWastedSpace ( vector < int >& packages , vector < vector < int >>& boxes ) { int n = packages . size (), m = boxes . size (); sort ( packages . begin (), packages . end ()); const int mod = 1e9 + 7 ; const long long inf = 1LL << 62 ; long long ans = inf ; for ( auto & box : boxes ) { sort ( box . begin (), box . end ()); if ( packages . back () > box . back ()) { continue ; } int i = 0 ; long long s = 0 ; for ( auto & b : box ) { int j = upper_bound ( packages . begin () + i , packages . end (), b ) - packages . begin (); s += 1LL * ( j - i ) * b ; i = j ; } ans = min ( ans , s ); } return ans == inf ? - 1 : ( ans - accumulate ( packages . begin (), packages . end (), 0LL )) % mod ; } };class Solution : def minWastedSpace ( self , packages : List [ int ], boxes : List [ List [ int ]]) -> int : mod = 10 ** 9 + 7 ans = inf packages . sort () for box in boxes : box . sort () if packages [ - 1 ] > box [ - 1 ]: continue s = i = 0 for b in box : j = bisect_right ( packages , b , lo = i ) s += ( j - i ) * b i = j ans = min ( ans , s ) if ans == inf : return - 1 return ( ans - sum ( packages )) % modVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.