1011. Capacity To Ship Packages Within D Days
Problem Description
You have a conveyor belt with packages that need to be shipped within a certain number of days. Each package has a specific weight given in the weights
array, where weights[i]
represents the weight of the i-th package.
The shipping process works as follows:
- You must load packages onto a ship each day in the exact order they appear on the conveyor belt (you cannot skip or rearrange packages)
- The ship has a weight capacity limit - the total weight of packages loaded on any single day cannot exceed this capacity
- Once you start loading the next day, you begin with a new empty ship
Your task is to find the minimum weight capacity the ship needs to have so that all packages can be shipped within the given number of days
.
For example, if weights = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
and days = 5
:
- With a ship capacity of 15, you could ship: Day 1: [1,2,3,4,5], Day 2: [6,7], Day 3: [8], Day 4: [9], Day 5: [10]
- This would successfully ship all packages within 5 days
The solution uses binary search to find the minimum capacity. The search range is between:
- Lower bound: The maximum weight among all packages (since the ship must be able to carry at least the heaviest package)
- Upper bound: The sum of all weights (which would allow shipping everything in one day)
The check
function determines if a given capacity allows shipping within the required days by simulating the loading process and counting how many days are needed.
Intuition
The key insight is recognizing that this is an optimization problem where we need to find the minimum value (ship capacity) that satisfies a condition (shipping within the given days). When we need to find a minimum or maximum value that satisfies certain constraints, binary search often comes into play.
Think about the relationship between ship capacity and the number of days needed:
- If we increase the ship's capacity, we can load more packages per day, reducing the total days needed
- If we decrease the ship's capacity, we need more days to ship everything
- This creates a monotonic relationship: higher capacity → fewer days, lower capacity → more days
Since there's this clear relationship, we can use binary search on the capacity. But what should our search range be?
The minimum possible capacity must be at least max(weights)
because the ship needs to carry the heaviest package. If the capacity is less than this, we can't ship that package at all.
The maximum capacity we'd ever need is sum(weights)
, which would allow us to ship everything in a single day. Any capacity higher than this would be wasteful.
Now, for any given capacity in this range, we can check if it's feasible by simulating the shipping process:
- Start loading packages in order
- When adding the next package would exceed the capacity, start a new day
- Count the total days needed
- If the days needed ≤ the allowed days, this capacity works
Since we want the minimum capacity that works, we binary search for the leftmost position where the condition is satisfied. The solution cleverly uses bisect_left
with a key
function that returns True
when the capacity is sufficient, effectively finding the minimum viable capacity.
Learn more about Binary Search patterns.
Solution Approach
The solution implements a binary search algorithm to find the minimum ship capacity. Here's how the implementation works:
Binary Search Setup:
left = max(weights)
: The minimum possible capacity (must carry the heaviest package)right = sum(weights) + 1
: One more than the maximum needed capacity (exclusive upper bound for the search range)
The Check Function:
The check(mx)
function determines if a given capacity mx
is sufficient to ship all packages within the allowed days:
def check(mx):
ws, cnt = 0, 1 # ws: current weight sum, cnt: days used (start with day 1)
for w in weights:
ws += w
if ws > mx: # Current load exceeds capacity
cnt += 1 # Start a new day
ws = w # Reset weight sum to current package
return cnt <= days # Check if we can ship within allowed days
The function simulates the loading process:
ws
tracks the cumulative weight loaded on the current daycnt
counts the number of days used (initialized to 1 since we start on day 1)- For each package, we try to add it to the current day's load
- If adding it would exceed capacity
mx
, we start a new day and put this package as the first item of the new day - Finally, we return
True
if the total days needed doesn't exceed the limit
Binary Search Execution:
return left + bisect_left(range(left, right), True, key=check)
This line uses Python's bisect_left
function cleverly:
range(left, right)
creates the search space of possible capacitieskey=check
transforms each capacity value to a boolean (True if sufficient, False if not)- Since larger capacities will return True and smaller ones False, we get a pattern like:
[False, False, ..., False, True, True, ..., True]
bisect_left
finds the leftmost position whereTrue
would be inserted, which is the minimum sufficient capacity- Adding
left
to the result gives us the actual capacity value sincebisect_left
returns an index
The time complexity is O(n * log(sum(weights) - max(weights)))
where n
is the length of the weights array, as we perform a binary search and each check operation takes O(n)
time.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with weights = [3, 2, 2, 4, 1, 4]
and days = 3
.
Step 1: Determine search boundaries
left = max(weights) = 4
(ship must carry the heaviest package)right = sum(weights) + 1 = 16 + 1 = 17
(upper bound for search)
Step 2: Binary search for minimum capacity
We'll test different capacities to find the minimum that works:
Testing capacity = 4:
- Day 1: Load [3] → total = 3 ✓
- Try adding 2 → total would be 5 > 4, so start new day
- Day 2: Load [2, 2] → total = 4 ✓
- Try adding 4 → total would be 8 > 4, so start new day
- Day 3: Load [4] → total = 4 ✓
- Try adding 1 → total would be 5 > 4, so start new day
- Day 4: Load [1] → total = 1 ✓
- Try adding 4 → total would be 5 > 4, so start new day
- Day 5: Load [4] → total = 4 ✓
Result: Need 5 days > 3 allowed days ✗
Testing capacity = 6:
- Day 1: Load [3, 2] → total = 5 ✓
- Try adding 2 → total would be 7 > 6, so start new day
- Day 2: Load [2, 4] → total = 6 ✓
- Try adding 1 → total would be 7 > 6, so start new day
- Day 3: Load [1, 4] → total = 5 ✓
Result: Need 3 days = 3 allowed days ✓
Binary search process: The actual binary search would proceed as:
- Search range: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
- Check results: [F, F, T, T, T, T, T, T, T, T, T, T, T]
bisect_left
finds the firstTrue
at index 2- Minimum capacity = 4 + 2 = 6
Final shipping arrangement with capacity 6:
- Day 1: [3, 2] (weight: 5)
- Day 2: [2, 4] (weight: 6)
- Day 3: [1, 4] (weight: 5)
The minimum ship capacity needed is 6.
Solution Implementation
1class Solution:
2 def shipWithinDays(self, weights: List[int], days: int) -> int:
3 """
4 Find the minimum ship capacity needed to ship all packages within given days.
5
6 Args:
7 weights: List of package weights
8 days: Maximum number of days to ship all packages
9
10 Returns:
11 Minimum ship capacity required
12 """
13
14 def can_ship_with_capacity(capacity):
15 """
16 Check if all packages can be shipped within the given days
17 using a ship with the specified capacity.
18
19 Args:
20 capacity: Maximum weight the ship can carry per day
21
22 Returns:
23 True if shipping is possible within days limit, False otherwise
24 """
25 current_weight = 0 # Current weight loaded on the ship
26 days_needed = 1 # Number of days needed (start with day 1)
27
28 for weight in weights:
29 current_weight += weight
30
31 # If adding this package exceeds capacity, start a new day
32 if current_weight > capacity:
33 days_needed += 1
34 current_weight = weight # Load this package on the new day
35
36 return days_needed <= days
37
38 # Binary search bounds:
39 # Minimum capacity: at least the heaviest package
40 # Maximum capacity: sum of all weights (ship everything in one day)
41 min_capacity = max(weights)
42 max_capacity = sum(weights) + 1 # +1 for exclusive upper bound
43
44 # Use binary search to find the minimum valid capacity
45 # bisect_left finds the leftmost position where the condition becomes True
46 from bisect import bisect_left
47 return min_capacity + bisect_left(
48 range(min_capacity, max_capacity),
49 True,
50 key=can_ship_with_capacity
51 )
52
1class Solution {
2 /**
3 * Finds the minimum ship capacity needed to ship all packages within the given days.
4 * Uses binary search to find the optimal capacity.
5 *
6 * @param weights Array of package weights to be shipped
7 * @param days Maximum number of days to ship all packages
8 * @return Minimum ship capacity required
9 */
10 public int shipWithinDays(int[] weights, int days) {
11 // Initialize binary search boundaries
12 // left: minimum possible capacity (at least the heaviest package)
13 // right: maximum possible capacity (sum of all weights - ship everything in one day)
14 int left = 0;
15 int right = 0;
16
17 for (int weight : weights) {
18 left = Math.max(left, weight); // Find the heaviest package
19 right += weight; // Calculate total weight
20 }
21
22 // Binary search for the minimum valid capacity
23 while (left < right) {
24 int mid = (left + right) >> 1; // Calculate midpoint using bit shift (equivalent to / 2)
25
26 if (canShipWithCapacity(mid, weights, days)) {
27 // If we can ship with this capacity, try to find a smaller one
28 right = mid;
29 } else {
30 // If we cannot ship with this capacity, we need a larger one
31 left = mid + 1;
32 }
33 }
34
35 return left; // left == right at this point, representing the minimum capacity
36 }
37
38 /**
39 * Checks if all packages can be shipped within the given days using the specified capacity.
40 *
41 * @param capacity Maximum weight capacity of the ship
42 * @param weights Array of package weights to be shipped
43 * @param days Maximum number of days allowed for shipping
44 * @return true if shipping is possible within days, false otherwise
45 */
46 private boolean canShipWithCapacity(int capacity, int[] weights, int days) {
47 int currentWeight = 0; // Current weight loaded on the ship
48 int daysNeeded = 1; // Number of days needed (start with day 1)
49
50 for (int weight : weights) {
51 currentWeight += weight;
52
53 // If adding this package exceeds capacity, start a new day
54 if (currentWeight > capacity) {
55 currentWeight = weight; // Start new day with current package
56 daysNeeded++; // Increment day counter
57 }
58 }
59
60 // Check if we can complete shipping within the allowed days
61 return daysNeeded <= days;
62 }
63}
64
1class Solution {
2public:
3 int shipWithinDays(vector<int>& weights, int days) {
4 // Initialize binary search boundaries
5 // minCapacity: must be at least the heaviest package
6 // maxCapacity: sum of all weights (ship everything in one day)
7 int minCapacity = 0;
8 int maxCapacity = 0;
9
10 for (const int& weight : weights) {
11 minCapacity = max(minCapacity, weight);
12 maxCapacity += weight;
13 }
14
15 // Lambda function to check if given capacity can ship all packages within required days
16 auto canShipWithCapacity = [&](int capacity) -> bool {
17 int currentWeight = 0; // Current weight loaded on the ship
18 int daysNeeded = 1; // Days needed with this capacity
19
20 for (const int& weight : weights) {
21 currentWeight += weight;
22
23 // If adding this package exceeds capacity, start a new day
24 if (currentWeight > capacity) {
25 currentWeight = weight; // Start new day with current package
26 daysNeeded++;
27 }
28 }
29
30 return daysNeeded <= days;
31 };
32
33 // Binary search for minimum capacity
34 while (minCapacity < maxCapacity) {
35 int midCapacity = minCapacity + (maxCapacity - minCapacity) / 2;
36
37 if (canShipWithCapacity(midCapacity)) {
38 // If we can ship with this capacity, try smaller capacity
39 maxCapacity = midCapacity;
40 } else {
41 // If we cannot ship with this capacity, need larger capacity
42 minCapacity = midCapacity + 1;
43 }
44 }
45
46 return minCapacity;
47 }
48};
49
1/**
2 * Find the minimum ship capacity to ship all packages within given days
3 * Uses binary search to find the optimal capacity
4 *
5 * @param weights - Array of package weights to be shipped
6 * @param days - Maximum number of days to ship all packages
7 * @returns The minimum ship capacity needed
8 */
9function shipWithinDays(weights: number[], days: number): number {
10 // Initialize binary search boundaries
11 // Minimum capacity must be at least the heaviest package
12 let minCapacity: number = 0;
13 // Maximum capacity would be carrying all packages at once
14 let maxCapacity: number = 0;
15
16 // Calculate the search boundaries
17 for (const weight of weights) {
18 minCapacity = Math.max(minCapacity, weight);
19 maxCapacity += weight;
20 }
21
22 /**
23 * Helper function to check if given capacity can ship all packages within days limit
24 *
25 * @param capacity - The ship capacity to test
26 * @returns True if all packages can be shipped within days limit, false otherwise
27 */
28 const canShipWithCapacity = (capacity: number): boolean => {
29 // Current day's weight sum
30 let currentWeight: number = 0;
31 // Number of days needed with this capacity
32 let daysNeeded: number = 1;
33
34 // Simulate loading packages day by day
35 for (const weight of weights) {
36 currentWeight += weight;
37
38 // If adding this package exceeds capacity, start a new day
39 if (currentWeight > capacity) {
40 currentWeight = weight;
41 daysNeeded++;
42 }
43 }
44
45 // Check if we can ship within the days limit
46 return daysNeeded <= days;
47 };
48
49 // Binary search for the minimum valid capacity
50 while (minCapacity < maxCapacity) {
51 // Calculate middle point (using bit shift for integer division)
52 const midCapacity: number = (minCapacity + maxCapacity) >> 1;
53
54 // If mid capacity works, try to find a smaller one
55 if (canShipWithCapacity(midCapacity)) {
56 maxCapacity = midCapacity;
57 } else {
58 // If mid capacity doesn't work, we need a larger capacity
59 minCapacity = midCapacity + 1;
60 }
61 }
62
63 // Return the minimum capacity found
64 return minCapacity;
65}
66
Time and Space Complexity
Time Complexity: O(n * log(sum(weights) - max(weights)))
The algorithm uses binary search on the range [max(weights), sum(weights)]
. The binary search space has a size of sum(weights) - max(weights) + 1
, which requires O(log(sum(weights) - max(weights)))
iterations.
For each binary search iteration, the check
function is called, which iterates through all n
elements in the weights
array once, taking O(n)
time.
Therefore, the overall time complexity is O(n * log(sum(weights) - max(weights)))
.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space:
- Variables
left
andright
for binary search boundaries - Variables
ws
andcnt
in thecheck
function - The
check
function itself doesn't use recursion or additional data structures
The range(left, right)
in bisect_left
is a generator in Python 3, which doesn't create the entire list in memory, so it doesn't affect space complexity.
Therefore, the space complexity is O(1)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Off-by-One Error in Day Counting Logic
A frequent mistake occurs when checking if the current load exceeds capacity. Many implementations incorrectly check the condition after adding the weight, leading to improper day counting:
Incorrect Implementation:
def can_ship_with_capacity(capacity):
current_weight = 0
days_needed = 1
for weight in weights:
if current_weight + weight > capacity: # Check before adding
days_needed += 1
current_weight = weight
else:
current_weight += weight # Add only if it fits
return days_needed <= days
Why it's wrong: This approach requires conditional logic to handle whether to add the weight or not, making the code more complex and error-prone.
Correct Implementation:
def can_ship_with_capacity(capacity):
current_weight = 0
days_needed = 1
for weight in weights:
current_weight += weight # Always add first
if current_weight > capacity: # Then check if exceeded
days_needed += 1
current_weight = weight # Reset to current package only
return days_needed <= days
Key Insight: By adding first and then checking, we simplify the logic. If the capacity is exceeded, we know the current package must start a new day, so we reset current_weight
to just that package's weight.
2. Incorrect Binary Search Bounds
Common Mistake: Setting the lower bound to 1 or 0 instead of max(weights)
:
# WRONG
min_capacity = 1 # or 0
# CORRECT
min_capacity = max(weights)
Why it matters: If the ship capacity is less than the heaviest package, that package can never be shipped, making the solution impossible. The minimum viable capacity must be at least the weight of the heaviest single package.
3. Forgetting to Initialize Day Count to 1
Incorrect:
days_needed = 0 # Starting with 0 days
Correct:
days_needed = 1 # We start shipping on day 1
Explanation: We begin shipping on day 1, not day 0. Starting with days_needed = 0
would undercount the total days by one, potentially returning an invalid (too small) capacity.
4. Using Inclusive Upper Bound Incorrectly
When using bisect_left
with a range, the upper bound should be exclusive:
Incorrect:
max_capacity = sum(weights)
bisect_left(range(min_capacity, max_capacity), ...) # Excludes sum(weights)
Correct:
max_capacity = sum(weights) + 1 # Add 1 for exclusive upper bound
bisect_left(range(min_capacity, max_capacity), ...)
Why it matters: If the only valid capacity is sum(weights)
(shipping everything in one day), the incorrect version would miss this value and could return an incorrect result or cause an error.
Which of the following is a min heap?
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!