🧠
Binary Search on Answer Space
💡 This approach uses binary search on the range of possible ship capacities, drastically reducing the number of checks needed. It introduces the key concept of a feasibility function guiding the search.
Intuition
Instead of checking every capacity, use binary search between max package weight and sum of weights. For each mid capacity, check if shipping is possible. Narrow down the search space based on feasibility.
Algorithm
- Set left as max weight and right as sum of weights.
- While left < right:
- Calculate mid as (left + right) // 2.
- Check if shipping is possible with capacity mid.
- If possible, move right to mid; else move left to mid + 1.
- Return left as the minimum capacity.
💡 The challenge is understanding why binary searching the answer space works and how the feasibility function guides the search.
def can_ship(weights, days, capacity):
day_count = 1
current_load = 0
for w in weights:
if current_load + w > capacity:
day_count += 1
current_load = 0
current_load += w
return day_count <= days
def ship_with_capacity_binary_search(weights, days):
left, right = max(weights), sum(weights)
while left < right:
mid = (left + right) // 2
if can_ship(weights, days, mid):
right = mid
else:
left = mid + 1
return left
# Driver code
if __name__ == '__main__':
weights = [1,2,3,4,5,6,7,8,9,10]
days = 5
print(ship_with_capacity_binary_search(weights, days))
Line Notes
def can_ship(weights, days, capacity):Defines feasibility check helper
for w in weights:Iterates over packages to simulate shipping
if current_load + w > capacity:Starts new day if capacity exceeded
return day_count <= daysReturns if shipping is possible within days
while left < right:Binary search loop over capacity range
mid = (left + right) // 2Calculate middle capacity to test
if can_ship(weights, days, mid):If feasible, try smaller capacity
else: left = mid + 1If not feasible, increase capacity
return leftMinimum capacity found
import java.util.*;
public class ShipCapacityBinarySearch {
public static boolean canShip(int[] weights, int days, int capacity) {
int dayCount = 1, currentLoad = 0;
for (int w : weights) {
if (currentLoad + w > capacity) {
dayCount++;
currentLoad = 0;
}
currentLoad += w;
}
return dayCount <= days;
}
public static int shipWithCapacityBinarySearch(int[] weights, int days) {
int left = Arrays.stream(weights).max().getAsInt();
int right = Arrays.stream(weights).sum();
while (left < right) {
int mid = left + (right - left) / 2;
if (canShip(weights, days, mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
public static void main(String[] args) {
int[] weights = {1,2,3,4,5,6,7,8,9,10};
int days = 5;
System.out.println(shipWithCapacityBinarySearch(weights, days));
}
}
Line Notes
public static boolean canShip(int[] weights, int days, int capacity)Feasibility check helper
for (int w : weights)Iterate over packages
if (currentLoad + w > capacity)Start new day if capacity exceeded
return dayCount <= daysReturn feasibility
while (left < right)Binary search loop over capacity
int mid = left + (right - left) / 2Calculate mid capacity safely
if (canShip(weights, days, mid))If feasible, try smaller capacity
else left = mid + 1If not feasible, increase capacity
return leftReturn minimum capacity
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
using namespace std;
bool canShip(const vector<int>& weights, int days, int capacity) {
int dayCount = 1, currentLoad = 0;
for (int w : weights) {
if (currentLoad + w > capacity) {
dayCount++;
currentLoad = 0;
}
currentLoad += w;
}
return dayCount <= days;
}
int shipWithCapacityBinarySearch(const vector<int>& weights, int days) {
int left = *max_element(weights.begin(), weights.end());
int right = accumulate(weights.begin(), weights.end(), 0);
while (left < right) {
int mid = left + (right - left) / 2;
if (canShip(weights, days, mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
int main() {
vector<int> weights = {1,2,3,4,5,6,7,8,9,10};
int days = 5;
cout << shipWithCapacityBinarySearch(weights, days) << endl;
return 0;
}
Line Notes
bool canShip(const vector<int>& weights, int days, int capacity)Feasibility helper function
for (int w : weights)Iterate over packages
if (currentLoad + w > capacity)Start new day if capacity exceeded
return dayCount <= daysReturn feasibility
while (left < right)Binary search loop
int mid = left + (right - left) / 2Calculate mid capacity safely
if (canShip(weights, days, mid))If feasible, try smaller capacity
else left = mid + 1If not feasible, increase capacity
return leftReturn minimum capacity
function canShip(weights, days, capacity) {
let dayCount = 1, currentLoad = 0;
for (let w of weights) {
if (currentLoad + w > capacity) {
dayCount++;
currentLoad = 0;
}
currentLoad += w;
}
return dayCount <= days;
}
function shipWithCapacityBinarySearch(weights, days) {
let left = Math.max(...weights);
let right = weights.reduce((a,b) => a+b, 0);
while (left < right) {
let mid = Math.floor((left + right) / 2);
if (canShip(weights, days, mid)) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
// Test
const weights = [1,2,3,4,5,6,7,8,9,10];
const days = 5;
console.log(shipWithCapacityBinarySearch(weights, days));
Line Notes
function canShip(weights, days, capacity)Feasibility check helper
for (let w of weights)Iterate over packages
if (currentLoad + w > capacity)Start new day if capacity exceeded
return dayCount <= daysReturn feasibility
while (left < right)Binary search loop over capacity
let mid = Math.floor((left + right) / 2)Calculate mid capacity
if (canShip(weights, days, mid))If feasible, try smaller capacity
else left = mid + 1If not feasible, increase capacity
return leftReturn minimum capacity
TimeO(n log S) where S = sum(weights) - max(weights)
SpaceO(1)
Binary search reduces the capacity search space logarithmically, and each feasibility check scans all weights once.
💡 For n=10^5 and sum(weights) ~ 5*10^7, this means about 10^5 * 25 = 2.5 million operations, which is efficient enough.
Interview Verdict: Accepted
This is the optimal approach for this problem and is expected in interviews.