Medium草稿★★★★★O(n * log(sum(weights))) 時間 · O(1) 空間
ArrayBinary Search
Patterns📐 二分答案🎯 二分搜尋
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

1011Capacity to Ship Packages Within D DaysBinary SearchMediumBinary Search

傳送帶上有 weights 代表的包裹(必須按順序運送),船的載重量為 capacity。每天船會裝載包裹直到無法再裝(不能超重)。求在 days 天內運完所有包裹的最小船載重量。

Example:

Input: weights = [1,2,3,4,5,6,7,8,9,10], days = 5 Output: 15

Intuition

TIP

在答案空間 [max(weights), sum(weights)] 上二分搜尋,找最小的載重量使得能在 days 天內完成。

Approaches

1. Linear Search — O(n * sum(weights)) / O(1)
  • Idea: 從 max(weights) 開始逐一嘗試載重量
  • Time: O(n * sum(weights))
  • Space: O(1)
Linear Search Code
class Solution {
    fun shipWithinDays(weights: IntArray, days: Int): Int {
        var cap = weights.max()
        while (true) {
            if (canShip(weights, days, cap)) return cap
            cap++
        }
    }

    private fun canShip(weights: IntArray, days: Int, cap: Int): Boolean {
        var daysNeeded = 1
        var currentLoad = 0
        for (w in weights) {
            if (currentLoad + w > cap) {
                daysNeeded++
                currentLoad = 0
            }
            currentLoad += w
        }
        return daysNeeded <= days
    }
}
⭐ 2. Binary Search on Answer Space — O(n * log(sum(weights))) / O(1)
  • Idea: 在 [max(weights), sum(weights)] 上二分搜尋最小可行的載重量
  • Time: O(n * log(sum(weights)))
  • Space: O(1)
class Solution {
    fun shipWithinDays(weights: IntArray, days: Int): Int {
        var left = weights.max()
        var right = weights.sum()
        while (left < right) {
            val mid = left + (right - left) / 2
            if (canShip(weights, days, mid)) {
                right = mid
            } else {
                left = mid + 1
            }
        }
        return left
    }

    private fun canShip(weights: IntArray, days: Int, cap: Int): Boolean {
        var daysNeeded = 1
        var currentLoad = 0
        for (w in weights) {
            if (currentLoad + w > cap) {
                daysNeeded++
                currentLoad = 0
            }
            currentLoad += w
        }
        return daysNeeded <= days
    }
}

WARNING

與 Koko Eating Bananas (#875) 是同一個模式:在答案空間上二分搜尋最小可行值。差別在於 feasibility check 的實作不同。

🔑 Takeaways

Ladders 看全部 →

🎯

二分搜尋「答案」

答案具單調性時,對答案值域二分。

  1. 1#875Koko Eating BananasMedium對吃香蕉速度二分
  2. 2
  3. 3#410Split Array Largest SumHard對「最大子陣列和」二分 + 貪心驗證