Topics › Binary Search › BS on Answers
Capacity to Ship Packages Within D Days
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
A conveyor belt holds n packages that must be shipped in the given order within days days. Every day we load the ship with packages from the front of the belt, in order, as long as the total weight does not exceed the ship’s capacity. Return the minimum capacity that lets all packages ship within days days.
Constraints: 1 ≤ n ≤ 5 * 10^4, 1 ≤ days ≤ n, 1 ≤ weights[i] ≤ 500.
Example 1
weights = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], days = 5
answer = 15 // days: [1,2,3,4,5] [6,7] [8] [9] [10]; capacity 14 would need 6 days
Example 2
weights = [3, 2, 2, 4, 1, 4], days = 3
answer = 6 // [3,2] [2,4] [1,4]
The order constraint is what makes this a partition problem: we are cutting the array into days contiguous blocks and want the heaviest block to be as light as possible.
The feasibility check
For a fixed capacity cap, how many days do we need? Load greedily: keep adding packages to the current day while they fit; when the next package would exceed cap, close the day and start a new one with that package. Greedy is optimal here because packages must go in order, so the only decision is where to cut, and delaying a cut for as long as possible never increases the number of days (any schedule that cuts earlier can be transformed into the greedy one without using more days).
static int daysNeeded(int[] weights, int cap) {
int days = 1;
long load = 0;
for (int w : weights) {
if (load + w > cap) { days++; load = 0; }
load += w;
}
return days;
}
The function assumes cap ≥ max(weights); otherwise the heaviest package would never fit on any day. Both approaches below guarantee that by starting the search at max. load is a long purely out of habit; with the given constraints an int suffices.
Approach 1: Brute force, try every capacity
Intuition. The capacity has a natural lower bound and upper bound. It must be at least max(weights), or the heaviest package cannot ship at all. It never needs to exceed sum(weights), because with that capacity everything ships in a single day. So the candidates are max, max + 1, ..., sum. A bigger ship never needs more days, so the first capacity from the small end that fits within days is the minimum.
Algorithm.
- Compute
maxandsumof the weights. - For
cap = max, max + 1, ..., sum: ifdaysNeeded(weights, cap) ≤ days, returncap. - Return
sum(never reached, sincecap = sumalways needs one day).
static int bruteForce(int[] weights, int days) {
int max = 0, sum = 0;
for (int w : weights) { max = Math.max(max, w); sum += w; }
for (int cap = max; cap <= sum; cap++) {
if (daysNeeded(weights, cap) <= days) return cap;
}
return sum;
}
Complexity. Time O(n * (sum - max)): with 5 * 10^4 packages of up to 500 the range has about 2.5 * 10^7 capacities, each checked in O(n), roughly 10^12 operations. Space O(1).
Approach 2: Optimal, binary search on the capacity
Intuition. Let fits(cap) = daysNeeded(weights, cap) ≤ days. If a capacity works, any larger capacity also works: the greedy loader with a bigger ship closes a day no earlier than with a smaller ship, so it never uses more days. Over cap = max, ..., sum the predicate is F F ... F T T ... T and we want the first T. Binary search over the capacity range: on a feasible mid record it and search smaller; otherwise search larger.
Algorithm.
- Compute
maxandsum; setlo = max,hi = sum,ans = sum. - While
lo ≤ hi:mid = lo + (hi - lo) / 2.- If
daysNeeded(weights, mid) ≤ days:ans = mid,hi = mid - 1. - Else:
lo = mid + 1.
- Return
ans.
static int optimal(int[] weights, int days) {
int max = 0, sum = 0;
for (int w : weights) { max = Math.max(max, w); sum += w; }
int lo = max, hi = sum, ans = sum;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (daysNeeded(weights, mid) <= days) { ans = mid; hi = mid - 1; }
else lo = mid + 1;
}
return ans;
}
Dry run on weights = [3, 2, 2, 4, 1, 4], days = 3 (max = 4, sum = 16):
| lo | hi | mid | greedy days at mid | days needed | ≤ 3? | ans | next |
|---|---|---|---|---|---|---|---|
| 4 | 16 | 10 | [3,2,2] [4,1,4] | 2 | yes | 10 | [4, 9] |
| 4 | 9 | 6 | [3,2] [2,4] [1,4] | 3 | yes | 6 | [4, 5] |
| 4 | 5 | 4 | [3] [2,2] [4] [1] [4] | 5 | no | 6 | [5, 5] |
| 5 | 5 | 5 | [3,2] [2] [4,1] [4] | 4 | no | 6 | [6, 5] stop |
Result 6.
Complexity. Time O(n log(sum)): about 25 iterations for sum ≤ 2.5 * 10^7, each an O(n) greedy scan, around 10^6 operations. Space O(1).
Why lo = max matters
Starting the search at lo = 1 is a classic bug. daysNeeded with a capacity below the heaviest package still returns some number because the greedy loop just starts a new day and then puts the oversized package on it anyway; it does not notice that the package does not fit. A capacity like that could then be reported as feasible. Starting at max guarantees every candidate is physically possible, and cap = sum guarantees the range contains at least one feasible value. In general, when you binary search on an answer, think about both ends: the low end must exclude impossible candidates, and the high end must include at least one feasible one.
Edge cases and pitfalls
- One day. The answer is
sum. The search recordssuminitially and never finds anything smaller that fits in one day. - As many days as packages. The answer is
max, because each package can have its own day. More days than packages is impossible by the constraints, but the code handles it the same way. - Single package.
[10]withdays = 1returns10; both bounds coincide. - Order matters.
[1, 2, 3, 1, 1]withdays = 4is3because the greedy loader forms[1,2] [3] [1,1]. You may not reorder packages to balance the days; this is not bin packing. - Capacity below
max. Covered above; always start atmax. - Overflow. With the stated limits
sum ≤ 2.5 * 10^7fits anint. If weights ornwere larger,sum,lo,hiandmidwould all need to belong. - Direction of the search. A feasible
midmoveshileft (we want the minimum). Flipping the branches returnssum.
Related problems
- Book Allocation Problem is the same partition problem with pages and students; the greedy counter is identical.
- Koko eating bananas and Find the smallest divisor use the same search skeleton with an arithmetic feasibility check.
- Aggressive Cows maximises instead of minimises, so the feasible side of the predicate is on the left.
- Minimum days to make M bouquets also relies on a greedy left-to-right scan for feasibility.