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 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 feasible(capacity):
15 """
16 Check if all packages can be shipped within the given days
17 using a ship with the specified capacity.
18 Returns True if capacity is sufficient (feasible), False otherwise.
19 """
20 current_weight = 0
21 days_needed = 1
22
23 for weight in weights:
24 current_weight += weight
25 if current_weight > capacity:
26 days_needed += 1
27 current_weight = weight
28
29 return days_needed <= days
30
31 # Binary search bounds
32 left = max(weights) # Minimum: must carry heaviest package
33 right = sum(weights) # Maximum: ship everything in one day
34 first_true_index = -1
35
36 # Binary search template: find first capacity where feasible(capacity) is True
37 while left <= right:
38 mid = (left + right) // 2
39 if feasible(mid):
40 first_true_index = mid
41 right = mid - 1 # Search for smaller valid capacity
42 else:
43 left = mid + 1
44
45 return first_true_index
461class Solution {
2 public int shipWithinDays(int[] weights, int days) {
3 // Initialize binary search boundaries
4 int left = 0;
5 int right = 0;
6
7 for (int weight : weights) {
8 left = Math.max(left, weight); // Minimum: must carry heaviest package
9 right += weight; // Maximum: ship everything in one day
10 }
11
12 int firstTrueIndex = -1;
13
14 // Binary search template: find first capacity where feasible(capacity) is True
15 while (left <= right) {
16 int mid = left + (right - left) / 2;
17
18 if (feasible(mid, weights, days)) {
19 firstTrueIndex = mid;
20 right = mid - 1; // Search for smaller valid capacity
21 } else {
22 left = mid + 1;
23 }
24 }
25
26 return firstTrueIndex;
27 }
28
29 private boolean feasible(int capacity, int[] weights, int days) {
30 int currentWeight = 0;
31 int daysNeeded = 1;
32
33 for (int weight : weights) {
34 currentWeight += weight;
35 if (currentWeight > capacity) {
36 currentWeight = weight;
37 daysNeeded++;
38 }
39 }
40
41 return daysNeeded <= days;
42 }
43}
441class Solution {
2public:
3 int shipWithinDays(vector<int>& weights, int days) {
4 // Initialize binary search boundaries
5 int left = 0;
6 int right = 0;
7
8 for (const int& weight : weights) {
9 left = max(left, weight); // Minimum: must carry heaviest package
10 right += weight; // Maximum: ship everything in one day
11 }
12
13 // Feasible function: check if capacity can ship all packages within days
14 auto feasible = [&](int capacity) -> bool {
15 int currentWeight = 0;
16 int daysNeeded = 1;
17
18 for (const int& weight : weights) {
19 currentWeight += weight;
20 if (currentWeight > capacity) {
21 currentWeight = weight;
22 daysNeeded++;
23 }
24 }
25
26 return daysNeeded <= days;
27 };
28
29 int firstTrueIndex = -1;
30
31 // Binary search template: find first capacity where feasible(capacity) is True
32 while (left <= right) {
33 int mid = left + (right - left) / 2;
34
35 if (feasible(mid)) {
36 firstTrueIndex = mid;
37 right = mid - 1; // Search for smaller valid capacity
38 } else {
39 left = mid + 1;
40 }
41 }
42
43 return firstTrueIndex;
44 }
45};
461function shipWithinDays(weights: number[], days: number): number {
2 // Initialize binary search boundaries
3 let left = 0;
4 let right = 0;
5
6 for (const weight of weights) {
7 left = Math.max(left, weight); // Minimum: must carry heaviest package
8 right += weight; // Maximum: ship everything in one day
9 }
10
11 // Feasible function: check if capacity can ship all packages within days
12 const feasible = (capacity: number): boolean => {
13 let currentWeight = 0;
14 let daysNeeded = 1;
15
16 for (const weight of weights) {
17 currentWeight += weight;
18 if (currentWeight > capacity) {
19 currentWeight = weight;
20 daysNeeded++;
21 }
22 }
23
24 return daysNeeded <= days;
25 };
26
27 let firstTrueIndex = -1;
28
29 // Binary search template: find first capacity where feasible(capacity) is True
30 while (left <= right) {
31 const mid = Math.floor((left + right) / 2);
32
33 if (feasible(mid)) {
34 firstTrueIndex = mid;
35 right = mid - 1; // Search for smaller valid capacity
36 } else {
37 left = mid + 1;
38 }
39 }
40
41 return firstTrueIndex;
42}
43Solution 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:
wstracks the cumulative weight loaded on the current daycntcounts 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
Trueif 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=checktransforms 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_leftfinds the leftmost position whereTruewould be inserted, which is the minimum sufficient capacity- Adding
leftto the result gives us the actual capacity value sincebisect_leftreturns 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_leftfinds the firstTrueat 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.
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
leftandrightfor binary search boundaries - Variables
wsandcntin thecheckfunction - The
checkfunction 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. Using Wrong Binary Search Template Variant
A common mistake is using while left < right with right = mid, which is a different binary search variant:
# WRONG - different template variant while left < right: mid = (left + right) // 2 if feasible(mid): right = mid else: left = mid + 1 return left
Correct template:
first_true_index = -1 while left <= right: mid = (left + right) // 2 if feasible(mid): first_true_index = mid right = mid - 1 else: left = mid + 1 return first_true_index
The template explicitly tracks the answer with first_true_index, uses while left <= right, and always moves right = mid - 1 when the condition is true.
2. Off-by-One Error in Day Counting Logic
A frequent mistake occurs when checking if the current load exceeds capacity:
Incorrect Implementation:
def feasible(capacity):
current_weight = 0
days_needed = 1
for weight in weights:
if current_weight + weight > capacity:
days_needed += 1
current_weight = weight
else:
current_weight += weight
return days_needed <= days
Correct Implementation:
def feasible(capacity):
current_weight = 0
days_needed = 1
for weight in weights:
current_weight += weight
if current_weight > capacity:
days_needed += 1
current_weight = weight
return days_needed <= days
By adding first and then checking, the logic is simpler: if capacity is exceeded, the current package starts a new day.
3. Incorrect Binary Search Bounds
Setting the lower bound to 1 or 0 instead of max(weights):
# WRONG
left = 1 # or 0
# CORRECT
left = max(weights)
The ship must carry at least the heaviest package.
4. Forgetting to Initialize Day Count to 1
# WRONG days_needed = 0 # CORRECT days_needed = 1
We begin shipping on day 1, not day 0.
What are the two properties the problem needs to have for dynamic programming to be applicable? (Select 2)
Recommended Readings
https assets algo monster cover_photos Binary_Search svg Binary Search Intuition Binary search is an efficient array search algorithm It works by narrowing down the search range by half each time If you have looked up a word in a physical dictionary you've already used binary search in real life Let's
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 If you prefer videos here's a video that explains recursion in a fun and easy way 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 him
Want a Structured Path to Master System Design Too? Don’t Miss This!