Capacity to Ship Packages Within D Days
1. The Core Problem Statement & Real-World Framing
When given an array of package weights and a specific number of days (), the goal is to determine the least capacity a ship must have to successfully transport all packages sequentially within days.
Real-Life Analogy: The Daily Cargo Ferry
Imagine you run a logistics service across a river. You have a single cargo ship that makes exactly one trip per day. You have customer packages lined up on the dock, each with a fixed weight (e.g., ).
- If your ship has a tiny capacity (e.g., ), it fills up quickly. Heavy packages get left behind on the dock, forcing you to stretch the shipping process across many days (e.g., 7 days instead of your target 5 days).
- If your ship has a massive capacity (e.g., ), you can load every single package on day one and finish instantly. However, building or renting a massive ship is unnecessarily expensive.
- The challenge is to find the absolute minimum ship capacity that allows you to clear the dock within your deadline of days.
2. Analyzing the Search Space: Establishing Lower & Upper Bounds
Before searching for the optimal capacity, we must determine the theoretical boundaries (minimum and maximum possible values) for the ship's capacity.
- Lower Bound (): Can a ship have a capacity smaller than the heaviest single package?
- No. If there is a package weighing , a ship with a capacity of could never load that package, making it impossible to ship all items. Therefore, .
- Upper Bound (): What is the maximum capacity we would ever need?
- If the ship's capacity equals the sum of all package weights, we can load every single item on the very first day. Any capacity larger than the sum is redundant. Therefore, .
Thus, the answer is guaranteed to lie within the inclusive range:
3. Naive Approach: Linear Search from Max to Sum
The most intuitive approach is to test every possible ship capacity sequentially, starting from up to , until we find the first capacity that satisfies the -day constraint.
Limitations of Linear Search
- Time Complexity: If the sum of weights is large, iterating linearly through every integer capacity takes time, which results in a quadratic-like time complexity that will fail on large test cases in an interview.
4. Designing the Feasibility Function (findDays)
To evaluate whether a given ship capacity is workable, we need a helper function that calculates how many days it takes to ship all packages under a fixed capacity constraint.
Algorithm Logic
- Start on
day = 1with a currentload = 0. - Iterate through each package weight from left to right.
- Check if adding the current package exceeds the ship's capacity:
- If it exceeds: Increment the day counter (
day++), and reset the load to the current package's weight. - If it fits: Add the package weight to the current day's load.
- If it exceeds: Increment the day counter (
- Return the total number of days required.
C++ Implementation of Feasibility Check
int findDays(vector<int>& weights, int capacity) {
int days = 1;
int load = 0;
for (int i = 0; i < weights.size(); i++) {
if (load + weights[i] > capacity) {
days = days + 1; // Move to the next day
load = weights[i]; // Load current package on the new day
} else {
load += weights[i]; // Keep loading on the current day
}
}
return days;
}
5. Dry Run of Feasibility Function
Consider an array of weights: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (Sum = 55, Max = 10). Let's test a capacity of 10 with target .
- Final Result: A capacity of requires 7 days. Since , capacity is invalid.
6. Optimized Approach: Binary Search on Answers
Since the search space is monotonically sorted (i.e., if capacity works, any capacity also works; if fails, any capacity also fails), we can apply Binary Search.
Binary Search Workflow
- Set and .
- Calculate .
- Pass
midas the test capacity intofindDays(weights, mid). - Evaluate Feasibility:
- If , the capacity is possible. Record it (or rely on binary search convergence) and try to find a smaller capacity by moving .
- If , the capacity is too small. Increase capacity by moving .
- Repeat until .
7. Step-by-Step Binary Search Execution Flow
8. Complete C++ Implementation
class Solution {
public:
int findDays(vector<int>& weights, int capacity) {
int days = 1;
int load = 0;
for (int i = 0; i < weights.size(); i++) {
if (load + weights[i] > capacity) {
days++;
load = weights[i];
} else {
load += weights[i];
}
}
return days;
}
int shipWithinDays(vector<int>& weights, int days) {
int low = *max_element(weights.begin(), weights.end());
int high = accumulate(weights.begin(), weights.end(), 0);
while (low <= high) {
int mid = low + (high - low) / 2;
int numberOfDays = findDays(weights, mid);
if (numberOfDays <= days) {
// Feasible capacity, try to find a smaller valid capacity on the left
high = mid - 1;
} else {
// Too small capacity, increase capacity by searching the right half
low = mid + 1;
}
}
return low; // Low pointer points to the minimum valid capacity
}
};
9. Complexity Analysis
10. Summary and Key Takeaways
- Problem Classification: This is a classic "Binary Search on Answers" problem where the answer range is bounded between the maximum element and the sum of elements.
- Lower Bound Rule: The minimum possible ship capacity can never be less than the single heaviest package in the dataset.
- Upper Bound Rule: The maximum sensible capacity is the sum of all package weights, allowing all items to be shipped in a single day.
- Monotonic Property: If a capacity can ship all packages within days, any capacity greater than will also work. If fails, anything smaller than will also fail.
- Helper Function Decoupling: Separating the day-counting logic into a helper function (
findDays) keeps the binary search clean and modular. - Pointer Convergence: When
low <= highterminates, thelowpointer naturally lands on the optimal minimum capacity. - Performance Gain: Optimizing from a linear search to binary search reduces the time complexity from quadratic-like behavior to efficient logarithmic time ().