Skip to content

1011. Capacity To Ship Packages Within D Days

class Solution:
    """🚢 Capacity To Ship Packages Within D Days.

    Problem:
    --------
    Given an array `weights` where `weights[i]` represents the weight of the i-th package,
    and an integer `days`, return the minimum ship capacity required to ship all packages
    within `days` days.

    Constraints:
    ------------
    - Packages must be shipped in order (no reordering allowed).
    - Each package must be shipped entirely in one day (no splitting).
    - The total weight shipped in a day cannot exceed the ship's capacity.

    Key Insight:
    ------------
    We are asked to minimize the ship capacity while satisfying a constraint (shipping within
    `days`).
    This is a classic **binary search on the answer space** problem.

    Observations:
    -------------
    - The minimum possible capacity is `max(weights)` (we must at least carry the heaviest package).
    - The maximum possible capacity is `sum(weights)` (ship everything in one day).
    - If a capacity `C` works (i.e., we can ship within `days`), then any capacity > C will also
    work.
      -> This monotonic property makes binary search applicable.

    Approach:
    ---------
    1. Perform binary search on the capacity range [max(weights), sum(weights)].
    2. For a candidate capacity:
       - Simulate the shipping process greedily:
         - Keep adding packages to the current day until capacity is exceeded.
         - Move to the next day when needed.
    3. If we can finish within `days`, try a smaller capacity.
       Otherwise, increase the capacity.

    Feasibility Check:
    ------------------
    Greedily pack packages:
    - If adding a package exceeds capacity -> move to next day.
    - Count how many days are needed.

    Complexity:
    -----------
    - Time: O(n * log(sum(weights) - max(weights)))
      - Binary search over capacity range
      - Each feasibility check is O(n)
    - Space: O(1)
    """

    def shipWithinDays(self, weights: list[int], days: int) -> int:
        low, high = max(weights), sum(weights)

        def can_ship(capacity: int) -> bool:
            days_needed = 1
            current_load = 0

            for w in weights:
                if current_load + w <= capacity:
                    current_load += w
                else:
                    days_needed += 1
                    current_load = w

            return days_needed <= days

        while low < high:
            mid = (low + high) // 2
            if can_ship(mid):
                high = mid
            else:
                low = mid + 1

        return low