You have the task of delivering some boxes from storage to their ports using only one ship. However, this ship has a limit on the number of boxes and the total weight that it can carry.
You are given an array boxes
, where boxes[i] = [portsi, weighti]
, and three integers portsCount
, maxBoxes
, and maxWeight
.
portsi
is the port where you need to deliver the ith
box and weightsi
is the weight of the ith
box.portsCount
is the number of ports.maxBoxes
and maxWeight
are the respective box and weight limits of the ship.The boxes need to be delivered in the order they are given. The ship will follow these steps:
boxes
queue, not violating the maxBoxes
and maxWeight
constraints.The ship must end at storage after all the boxes have been delivered.
Return the minimum number of trips the ship needs to make to deliver all boxes to their respective ports.
Example 1:
Input: boxes = [[1,1],[2,1],[1,1]], portsCount = 2, maxBoxes = 3, maxWeight = 3 Output: 4 Explanation: The optimal strategy is as follows: - The ship takes all the boxes in the queue, goes to port 1, then port 2, then port 1 again, then returns to storage. 4 trips. So the total number of trips is 4. Note that the first and third boxes cannot be delivered together because the boxes need to be delivered in order (i.e. the second box needs to be delivered at port 2 before the third box).
Example 2:
Input: boxes = [[1,2],[3,3],[3,1],[3,1],[2,4]], portsCount = 3, maxBoxes = 3, maxWeight = 6 Output: 6 Explanation: The optimal strategy is as follows: - The ship takes the first box, goes to port 1, then returns to storage. 2 trips. - The ship takes the second, third and fourth boxes, goes to port 3, then returns to storage. 2 trips. - The ship takes the fifth box, goes to port 2, then returns to storage. 2 trips. So the total number of trips is 2 + 2 + 2 = 6.
Example 3:
Input: boxes = [[1,4],[1,2],[2,1],[2,1],[3,2],[3,4]], portsCount = 3, maxBoxes = 6, maxWeight = 7 Output: 6 Explanation: The optimal strategy is as follows: - The ship takes the first and second boxes, goes to port 1, then returns to storage. 2 trips. - The ship takes the third and fourth boxes, goes to port 2, then returns to storage. 2 trips. - The ship takes the fifth and sixth boxes, goes to port 3, then returns to storage. 2 trips. So the total number of trips is 2 + 2 + 2 = 6.
Constraints:
1 <= boxes.length <= 105
1 <= portsCount, maxBoxes, maxWeight <= 105
1 <= portsi <= portsCount
1 <= weightsi <= maxWeight
This problem can be solved efficiently using dynamic programming, enhanced with a monotonic queue for optimization.
Understanding the Problem
We need to deliver boxes from storage to ports, respecting constraints on the number of boxes and total weight the ship can carry. Boxes must be delivered in order. The goal is to minimize the total number of trips the ship makes. Each trip consists of loading boxes, delivering them (potentially multiple port stops within a single trip), and returning to storage.
Approach
Dynamic Programming: We define dp[i]
as the minimum number of trips needed to deliver the first i
boxes. The state transition involves considering the last trip: we iterate through possible ending points j
for the last trip (from i - maxBoxes
to i - 1
), and calculate the cost of that trip.
Calculating Trip Cost: A single trip's cost depends on:
i - j
).cs
to count port changes efficiently.Monotonic Queue Optimization: The dynamic programming recurrence requires checking all possible j
values in a window, leading to O(n^2) complexity. The monotonic queue optimizes this. It stores indices j
that minimize dp[j] - cs[j]
. This allows us to find the optimal j
in O(1) time for each i
. The queue is monotonic because we only need to maintain the minimum value; elements with larger values won't improve the solution.
Time Complexity Analysis:
n
times.Space Complexity Analysis:
O(n)
space for the dp
array, ws
(weight prefix sum), cs
(port change prefix sum), and the monotonic queue.Code Implementation (Python):
from itertools import accumulate, pairwise
from collections import deque
class Solution:
def boxDelivering(self, boxes, portsCount, maxBoxes, maxWeight):
n = len(boxes)
ws = list(accumulate(box[1] for box in boxes)) # Prefix sum of weights
c = [int(a != b) for a, b in pairwise(box[0] for box in boxes)] # Port change indicator
cs = list(accumulate(c)) # Prefix sum of port changes
dp = [0] * (n + 1)
q = deque([0])
for i in range(1, n + 1):
while q and (i - q[0] > maxBoxes or ws[i] - ws[q[0]] > maxWeight):
q.popleft()
if q:
dp[i] = dp[q[0]] + cs[i-1] - cs[q[0]] + 2 # Update dp[i] using the best j from the queue
if i < n:
while q and dp[q[-1]] - cs[q[-1]] >= dp[i] - cs[i]:
q.pop()
q.append(i) # Add i to the queue if it can improve the solution
return dp[n]
Other Languages:
The solution can be adapted to other languages like Java, C++, and Go using similar data structures and logic. The core algorithm remains the same. The code structure might vary slightly depending on the language's built-in features (e.g., deque implementations). For brevity, I am not including the other languages here, but the adaptation would be straightforward.