Problem overview
The method maximumUnits receives boxTypes, an Array[Array[Int]] in which each entry is [numberOfBoxes, unitsPerBox], and truckSize, the most boxes the truck can carry. It returns the largest total number of units that fit on the truck.
In the first example, boxTypes = [[1, 3], [2, 2], [3, 1]] and truckSize = 4. Take the one box with 3 units, the two boxes with 2 units, and one of the boxes with 1 unit: 3 + 4 + 1 = 8. In the second example, [[5, 10], [2, 5], [4, 7], [3, 9]] with truckSize = 10, the answer is 91. The constraints allow up to 1000 box types and up to 1000 boxes of each type, and a truck of up to a million boxes.
Approach: densest boxes first
Every box takes exactly one slot, whatever it holds. So each slot should carry the box with the most units available. That makes a greedy strategy correct: sort the box types by units per box, largest first, then load from the front until the truck is full.
Swapping a loaded box for one with more units never reduces the total, and never uses an extra slot, so no better plan can skip a denser box in favour of a lighter one. The number of boxes per type only limits how many of that type you can take.
Trace the first example. Sorted by units per box, the order is already [1, 3], [2, 2], [3, 1]. The first type contributes 1 box (3 units) and leaves 3 slots, the second contributes 2 boxes (4 units) and leaves 1, and the third contributes min(3, 1) = 1 box (1 unit) and leaves 0. The total is 8.
The second example works the same way. Sorted from most to fewest units per box, the types are [5, 10], [3, 9], [4, 7] and [2, 5]. The first takes 5 boxes for 50 units and leaves 5 slots. The second takes all 3 boxes for 27 more units, 77 in total, and leaves 2 slots. The third takes only 2 of its 4 boxes, for 14 units, which brings the total to 91. The last type then takes 0 boxes.
Step by step
- Sort by units per box, largest first.
sortBysorts by the key its function returns, in increasing order, so the key is the negative of the units:-b(1). The result goes into a new array,sorted. - Set up two
vars.unitsis the running total, starting at 0.remainingstarts attruckSize. Parameters can't be reassigned in Scala, so the changing capacity lives in its own variable. - Loop over
sorted, with eachboxbeing a[count, unitsPerBox]pair:box(0)is how many boxes of the type exist andbox(1)is the units in each. - Decide how many to take:
math.min(box(0), remaining). You can't take more than exist or more than still fit. - Add the units that those boxes contribute:
take * box(1). - Use up the capacity by subtracting
takefromremaining. Scala has nobreakstatement, so the loop simply keeps going. Onceremainingis 0 every latertakeis 0 and adds nothing. - End with
unitsas the last expression.
The solution in Scala
class Solution {
def maximumUnits(boxTypes: Array[Array[Int]], truckSize: Int): Int = {
val sorted = boxTypes.sortBy(b => -b(1))
var units = 0
var remaining = truckSize
for (box <- sorted) {
val take = math.min(box(0), remaining)
units += take * box(1)
remaining -= take
}
units
}
}
The Scala details worth a closer look:
sortByreturns a new array. The caller'sboxTypeskeeps its original order. The sort is stable, so box types with equal units keep their relative order, which doesn't change the total.- Sorting in decreasing order.
sortByhas no direction option, so negating the key is the quickest way. Because the units are at most 1000, the negation can't overflow. Reversing the sorted array also works. Intis enough. It has 32 bits and wraps silently on overflow. The largest possible total is a million boxes times 1000 units, which is 1,000,000,000. That is below theIntlimit of 2,147,483,647.- Lambda shorthand.
b => -b(1)is an anonymous function that takes a box type and returns its sort key.
Complexity
Let n be the number of box types.
Time: O(n log n). Sorting dominates. The loop is O(n).
Space: O(n). sortBy builds a new array of the same length. The array holds references to the original pairs rather than copies of them.
Edge cases and common mistakes
- A truck bigger than the load.
[[1, 5]]withtruckSize = 10returns 5. The truck is not filled, andremainingends at 9. - A truck smaller than one type.
[[5, 10]]withtruckSize = 2returns 20, becausetakeis capped byremaining. - The largest input. With 1000 types of 1000 boxes holding 1000 units each and
truckSize = 1000000, the result is 1000000000, with no overflow. - Sorting by box count. The first element is how many boxes exist, not how valuable they are. Sorting by
b(0)gives wrong answers. - Forgetting the negative sign. Without it the sort is increasing, and the truck fills with the lightest boxes first.
- Multiplying before capping. Use
take, notbox(0), when adding units.
Testing
[[1, 3], [2, 2], [3, 1]],truckSize = 4gives8.[[5, 10], [2, 5], [4, 7], [3, 9]],truckSize = 10gives91.[[5, 10]],truckSize = 2gives20.[[1, 5]],truckSize = 10gives5.
