From 1f93c2940eeca7483221f17f3caf59c42f3c8531 Mon Sep 17 00:00:00 2001 From: Ryohei Sato <130881456+Satorien@users.noreply.github.com> Date: Sat, 13 Sep 2025 22:48:33 +0900 Subject: [PATCH] Create 1011. Capacity To Ship Packages Within D Days.md --- ...Capacity To Ship Packages Within D Days.md | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Python3/1011. Capacity To Ship Packages Within D Days.md diff --git a/Python3/1011. Capacity To Ship Packages Within D Days.md b/Python3/1011. Capacity To Ship Packages Within D Days.md new file mode 100644 index 0000000..744596c --- /dev/null +++ b/Python3/1011. Capacity To Ship Packages Within D Days.md @@ -0,0 +1,131 @@ +## Step 1. Initial Solution + +- シンプルに可能性のある値からスタートして実験して成功しなければ+1してみる + - 可能性のある値としては、最大値と合計/日数の大きい方 + - 本当は+1していくよりも効率的なやり方があるような気もするが一旦これで実装 + +```python +class Solution: + def shipWithinDays(self, weights: List[int], days: int) -> int: + min_capacity = max(max(weights), sum(weights) // days) + daily_capacity = min_capacity + days_left = days + while True: + for weight in weights: + if daily_capacity < weight: + days_left -= 1 + daily_capacity = min_capacity + if days_left == 0: + break + daily_capacity -= weight + if days_left > 0: + return min_capacity + days_left = days + min_capacity += 1 + daily_capacity = min_capacity +``` + +### Complexity Analysis + +- 時間計算量:O(xn) + - 答えを見つけるまでにwhile文を回す回数x + - 最大いくつまで行けるかはよく分かっていなかったが重量の合計まで上げれば確実にOK + - 重量のリスト長n +- 空間計算量:O(1) + - 追加で必要な変数は3個分 + +## Step 2. Alternatives + +- max(weights)とsum(weights)の間に答えがあると考えられる(!)のでこれを用いて二分探索する方法がある + - これがどれだけ速いのかをよく理解できていない + - 元々期待値として線形に船の容量を上げるとどうなるのか? +- bisect_leftの引数に自分で定義した関数を渡す方法 + - https://github.com/tokuhirat/LeetCode/pull/44/files#diff-06f87195f0dc2635b3c326a3257c212b916a27bd5f47afbf0368d37831b513a3R29 + - 個人的にはまだ慣れていないがシンプルに書けていると感じる + - rangeをbisect_leftの探索対象のリストに入れている + - 省メモリ + - https://github.com/Fuminiton/LeetCode/pull/44/files#r2129170877 +- 他にも同じような発想が多い + - https://github.com/Fuminiton/LeetCode/pull/44/files + - https://github.com/nittoco/leetcode/pull/47/files + - いつも思うがなぜ皆同じような解法になっているんだろうか?自分だけ何かを理解できていないような気分 + - 取りあえず今回のような範囲を思いつきにくい場合でも二分探索を軸に考えるのは一般的と理解しておく +- days=0の時の考慮 + - 無限ループになってしまう + - 初めに弾いておくべき + - https://github.com/nittoco/leetcode/pull/47/files#diff-4e146417f14c744a10f851601f26cd2cb17b420ff966720e568f6f5679aa475eR79 +- こういう秒数の見積もりを自然にやりたい + - https://github.com/Fuminiton/LeetCode/pull/44/files#diff-26f729e002c5c9244ef5172608184baffaf2040258f34729cff27b841079b595R18 +- 二分探索での実装 + + ```python + class Solution: + def shipWithinDays(self, weights: List[int], days: int) -> int: + if not weights: + return 0 + if days <= 0: + return -1 + + def canShipWithCapacity(capacity: int) -> bool: + days_left = days + daily_capacity_left = capacity + for weight in weights: + if daily_capacity_left < weight: + days_left -= 1 + daily_capacity_left = capacity + if days_left == 0: + return False + daily_capacity_left -= weight + return True + + left = max(weights) + right = sum(weights) + while left < right: + middle = (left + right) // 2 + if canShipWithCapacity(middle): + right = middle + else: + left = middle + 1 + return left + ``` + + +## Step 3. Final Solution + +- 自作関数をbisect_leftに渡すのを練習 + - loを使わない方法としては以下がある + + ```python + return bisect_left( + range(max(weights), sum(weights) + 1), + True, + key=canShipWithCapacity + ) + max(weights) + ``` + + +```python +class Solution: + def shipWithinDays(self, weights: List[int], days: int) -> int: + if days <= 0: + return -1 + if not weights: + return 0 + + def canShipWithCapacity(capacity: int) -> bool: + daily_load = 0 + required_days = 1 + for weight in weights: + daily_load += weight + if daily_load > capacity: + required_days += 1 + daily_load = weight + return required_days <= days + + return bisect_left( + range(sum(weights) + 1), + True, + lo=max(weights), + key=canShipWithCapacity + ) +```