From dd2cee8316177323b5d350f748863980d5bebc33 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sat, 13 Sep 2025 13:21:00 +0900 Subject: [PATCH 1/7] Solve 1011_capacity_to_ship_packages_within_d_days_medium --- .../README.md | 134 ++++++++++++++++++ .../step1.py | 37 +++++ .../step2.py | 37 +++++ .../use_bisect.py | 29 ++++ 4 files changed, 237 insertions(+) create mode 100644 1011_capacity_to_ship_packages_within_d_days_medium/README.md create mode 100644 1011_capacity_to_ship_packages_within_d_days_medium/step1.py create mode 100644 1011_capacity_to_ship_packages_within_d_days_medium/step2.py create mode 100644 1011_capacity_to_ship_packages_within_d_days_medium/use_bisect.py diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/README.md b/1011_capacity_to_ship_packages_within_d_days_medium/README.md new file mode 100644 index 0000000..a556bcd --- /dev/null +++ b/1011_capacity_to_ship_packages_within_d_days_medium/README.md @@ -0,0 +1,134 @@ +# 問題へのリンク +[Capacity To Ship Packages Within D Days](https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/) + +# 言語 +Python + +# 問題の概要 + + +# 自分の解法 + +## step1 + +```python +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + if not weights: + return 0 + + def can_ship_within_days(days: int, capacity: int) -> bool: + cargo_weight = 0 + days_required = 1 + for weight in weights: + if weight > capacity: + return False + if cargo_weight + weight > capacity: + cargo_weight = 0 + days_required += 1 + cargo_weight += weight + return days_required <= days + + # 0 < capacity <= sum weights + left = 0 + right = sum(weights) + while right - left > 1: + mid = (right + left) // 2 + if can_ship_within_days(days, mid): + right = mid + else: + left = mid + return right +``` + +- 単調性あるところに二分探索あり。 +- `(left, right]`の範囲で二分探索するパターン。 +- `can_ship_within_days`関数内で`weight > capacity`のチェックをしているが、はじめは抜けていた上、なかなか気づきづらい。 + - `left`の初期値を`0`にしていたが、`max(weights)`などにすればこのチェックは不要になる。その場合、二分探索も変わる。 + - そうはいっても、そもそも`if max(weights) > capacity: return False`とすべき。 + - 例えば`weights = [100,]`のとき、can_ship_within_days(2, 50)は`False`を返すべきだが、上記のコードでは`True`を返してしまう。これは2日に分ければ大きな荷物も運べるということになってしまうため。 +- `cargo_weight`は複数の荷物をまとめた重さを表す変数としているが、`current_weight`の方がわかりやすいと思った +- `can_ship_within_days`という名前の関数で`days`が引数にないのは違和感があるので、`days`を引数にした。が、`can_ship`にリネームして`days`をキャプチャする形にしたほうが自然だと思った。 + +`weights`の要素数を`N`、`weights`の要素の和を`S`とすると、 +- 時間計算量:`O(N log(S))` +- 空間計算量:`O(N)` + +## step2 + +```python +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + if not weights: + return 0 + + def can_ship(capacity: int) -> bool: + current_weight = 0 + days_required = 1 + for weight in weights: + if current_weight + weight > capacity: + current_weight = 0 + days_required += 1 + current_weight += weight + return days_required <= days + + # max weight <= capacity <= sum weights + left = max(weights) - 1 + right = sum(weights) + while right - left > 1: + mid = (right + left) // 2 + if can_ship(mid): + right = mid + else: + left = mid + return right +``` +- `can_ship_within_days`関数を`can_ship`にリネーム + + +## step3 + +## step4 (FB) + + + +# 別解・模範解答 +`bisect`モジュールを使う方法 + +```python +import bisect + + +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + def can_ship(capacity: int) -> bool: + if max(weights) > capacity: + return False + current_weight = 0 + days_required = 1 + for weight in weights: + current_weight += weight + if current_weight > capacity: + days_required += 1 + current_weight = weight + return days_required <= days + + return bisect.bisect_left(range(sum(weights) + 1), True, key=can_ship) +``` + +- 二分探索を自分で書く前に、まずは`bisect`モジュールを使って通るかを見るのが良い。 +- `bisect`モジュールでは`key`引数が使えるので、`can_ship`関数をそのまま渡せる。 +- ソート済みのリストを用意する必要があるが、`range`で用意できる。`bool`の配列ではソートすると`False`が先に来るので、`True`が初めて出現するインデックスを求めることになる。 + + +# 想定されるフォローアップ質問 + +## CS 基礎 + +## システム設計 + +## その他 + +# 次に解く問題の予告 +- [Unique Paths II](https://leetcode.com/problems/unique-paths-ii/) +- [Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/step1.py b/1011_capacity_to_ship_packages_within_d_days_medium/step1.py new file mode 100644 index 0000000..c4356ea --- /dev/null +++ b/1011_capacity_to_ship_packages_within_d_days_medium/step1.py @@ -0,0 +1,37 @@ +# +# @lc app=leetcode id=1011 lang=python3 +# +# [1011] Capacity To Ship Packages Within D Days +# + +# @lc code=start +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + if not weights: + return 0 + + def can_ship_within_days(days: int, capacity: int) -> bool: + cargo_weight = 0 + days_required = 1 + for weight in weights: + if weight > capacity: + return False + if cargo_weight + weight > capacity: + cargo_weight = 0 + days_required += 1 + cargo_weight += weight + return days_required <= days + + # 0 < capacity <= sum weights + left = 0 + right = sum(weights) + while right - left > 1: + mid = (right + left) // 2 + if can_ship_within_days(days, mid): + right = mid + else: + left = mid + return right + + +# @lc code=end diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/step2.py b/1011_capacity_to_ship_packages_within_d_days_medium/step2.py new file mode 100644 index 0000000..5ff6622 --- /dev/null +++ b/1011_capacity_to_ship_packages_within_d_days_medium/step2.py @@ -0,0 +1,37 @@ +# +# @lc app=leetcode id=1011 lang=python3 +# +# [1011] Capacity To Ship Packages Within D Days +# + +# @lc code=start +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + if not weights: + return 0 + + def can_ship(capacity: int) -> bool: + if max(weights) > capacity: + return False + current_weight = 0 + days_required = 1 + for weight in weights: + if current_weight + weight > capacity: + current_weight = 0 + days_required += 1 + current_weight += weight + return days_required <= days + + # max weight <= capacity <= sum weights + left = 0 + right = sum(weights) + while right - left > 1: + mid = (right + left) // 2 + if can_ship(mid): + right = mid + else: + left = mid + return right + + +# @lc code=end diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/use_bisect.py b/1011_capacity_to_ship_packages_within_d_days_medium/use_bisect.py new file mode 100644 index 0000000..d70d93a --- /dev/null +++ b/1011_capacity_to_ship_packages_within_d_days_medium/use_bisect.py @@ -0,0 +1,29 @@ +# +# @lc app=leetcode id=1011 lang=python3 +# +# [1011] Capacity To Ship Packages Within D Days +# + +# @lc code=start + +import bisect + + +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + def can_ship(capacity: int) -> bool: + if max(weights) > capacity: + return False + current_weight = 0 + days_required = 1 + for weight in weights: + current_weight += weight + if current_weight > capacity: + days_required += 1 + current_weight = weight + return days_required <= days + + return bisect.bisect_left(range(sum(weights) + 1), True, key=can_ship) + + +# @lc code=end From 07f3819a091ecc0f5cd66c09bdb4836d160cbc85 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sat, 13 Sep 2025 13:21:52 +0900 Subject: [PATCH 2/7] Add step3 file (no implementations) --- .../step3.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 1011_capacity_to_ship_packages_within_d_days_medium/step3.py diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/step3.py b/1011_capacity_to_ship_packages_within_d_days_medium/step3.py new file mode 100644 index 0000000..59a6c08 --- /dev/null +++ b/1011_capacity_to_ship_packages_within_d_days_medium/step3.py @@ -0,0 +1,11 @@ +# +# @lc app=leetcode id=1011 lang=python3 +# +# [1011] Capacity To Ship Packages Within D Days +# + +# @lc code=start +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + return 0 +# @lc code=end From a9921efb4e89cfebe1469954b177bce7652b4ccb Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 14 Sep 2025 14:06:19 +0900 Subject: [PATCH 3/7] Add step3 --- .../step3.py | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/step3.py b/1011_capacity_to_ship_packages_within_d_days_medium/step3.py index 59a6c08..06db1a6 100644 --- a/1011_capacity_to_ship_packages_within_d_days_medium/step3.py +++ b/1011_capacity_to_ship_packages_within_d_days_medium/step3.py @@ -7,5 +7,30 @@ # @lc code=start class Solution: def shipWithinDays(self, weights: list[int], days: int) -> int: - return 0 + # for given capacity, we can check if we can ship all the packages with it + def can_ship(capacity: int) -> bool: + if max(weights) > capacity: + return False + + current_weight = 0 + days_required = 1 + for weight in weights: + current_weight += weight + if current_weight > capacity: + current_weight = weight + days_required += 1 + return days_required <= days + + left = 0 + right = sum(weights) + while right - left > 1: + mid = (right + left) // 2 + if can_ship(mid): + right = mid + else: + left = mid + + return right + + # @lc code=end From 8d5dccb56fe96e5f6356158e6153eab5ba8b68bf Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 14 Sep 2025 14:07:23 +0900 Subject: [PATCH 4/7] Add implementation for step3 in README --- .../README.md | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/README.md b/1011_capacity_to_ship_packages_within_d_days_medium/README.md index a556bcd..af75aa6 100644 --- a/1011_capacity_to_ship_packages_within_d_days_medium/README.md +++ b/1011_capacity_to_ship_packages_within_d_days_medium/README.md @@ -4,8 +4,6 @@ # 言語 Python -# 問題の概要 - # 自分の解法 @@ -87,6 +85,34 @@ class Solution: ## step3 +```python +class Solution: + def shipWithinDays(self, weights: list[int], days: int) -> int: + # for given capacity, we can check if we can ship all the packages with it + def can_ship(capacity: int) -> bool: + if max(weights) > capacity: + return False + + current_weight = 0 + days_required = 1 + for weight in weights: + current_weight += weight + if current_weight > capacity: + current_weight = weight + days_required += 1 + return days_required <= days + + left = 0 + right = sum(weights) + while right - left > 1: + mid = (right + left) // 2 + if can_ship(mid): + right = mid + else: + left = mid + + return right +``` ## step4 (FB) From 238d0e4f557a21b9b6dfd8c167f7001cba19b66b Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 14 Sep 2025 14:08:04 +0900 Subject: [PATCH 5/7] Update README --- .../README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/README.md b/1011_capacity_to_ship_packages_within_d_days_medium/README.md index af75aa6..2c32240 100644 --- a/1011_capacity_to_ship_packages_within_d_days_medium/README.md +++ b/1011_capacity_to_ship_packages_within_d_days_medium/README.md @@ -147,14 +147,6 @@ class Solution: - ソート済みのリストを用意する必要があるが、`range`で用意できる。`bool`の配列ではソートすると`False`が先に来るので、`True`が初めて出現するインデックスを求めることになる。 -# 想定されるフォローアップ質問 - -## CS 基礎 - -## システム設計 - -## その他 - # 次に解く問題の予告 - [Unique Paths II](https://leetcode.com/problems/unique-paths-ii/) - [Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/) From 1b5263d4e26077195261b3b8b92908d1ea7642ea Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 14 Sep 2025 15:47:38 +0900 Subject: [PATCH 6/7] Add example for MyRange class to demonstrate bisect usage --- .../README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/README.md b/1011_capacity_to_ship_packages_within_d_days_medium/README.md index 2c32240..a350972 100644 --- a/1011_capacity_to_ship_packages_within_d_days_medium/README.md +++ b/1011_capacity_to_ship_packages_within_d_days_medium/README.md @@ -145,6 +145,25 @@ class Solution: - 二分探索を自分で書く前に、まずは`bisect`モジュールを使って通るかを見るのが良い。 - `bisect`モジュールでは`key`引数が使えるので、`can_ship`関数をそのまま渡せる。 - ソート済みのリストを用意する必要があるが、`range`で用意できる。`bool`の配列ではソートすると`False`が先に来るので、`True`が初めて出現するインデックスを求めることになる。 +- `bisect`に渡せる配列は`SupportsLenAndGetItem`プロトコルを満たしていれば良いので、`__len__`と`__getitem__`を実装したクラスならば良い。 + +```python +import bisect + +class MyRange: + def __init__(self): + self.length = 5 + + def __len__(self): + return self.length + + def __getitem__(self, key: int) -> int: + return 2 * key + + +g = MyRange() # [0, 2, 4, 6, 8] +bisect.bisect_left(g, 3) # 2 +``` # 次に解く問題の予告 From 987c8f9c634913b0d7659d89951f201063943478 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Mon, 15 Sep 2025 15:25:01 +0900 Subject: [PATCH 7/7] Rename binary search variables for clarity in step4 --- 1011_capacity_to_ship_packages_within_d_days_medium/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/1011_capacity_to_ship_packages_within_d_days_medium/README.md b/1011_capacity_to_ship_packages_within_d_days_medium/README.md index a350972..3cc8948 100644 --- a/1011_capacity_to_ship_packages_within_d_days_medium/README.md +++ b/1011_capacity_to_ship_packages_within_d_days_medium/README.md @@ -115,7 +115,9 @@ class Solution: ``` ## step4 (FB) - +- 二分探索の `left`/`right`という変数名を問題に適した名前に変える。これで不変条件がわかりやすくなる。 + - `left` -> `insufficient_capacity` + - `right` -> `sufficient_capacity` # 別解・模範解答