Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions medium/1011/answer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Step1

かかった時間:33min

計算量:N = len(weights), M = sum(weights)として

時間計算量:O(NlogM)

空間計算量:O(1)

```python
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
def can_ship_capacity_in_days(capacity: int, days: int) -> bool:
total_weight = 0
i = 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iはちょっとわかりにくい気がします
weight_index
とかどうでしょうか

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for i in range(len(array)): と書かれたら、i が array の添字だと思うと思うんですね。これを長々と説明的に書かれてもありがたくないのです。あと、この for を抜けたらもう忘れて良いやつだというのが暗に含意されています。
これが、for first_zero_index in だったら途中で見つけて break するから抜けても覚えている必要があるものでしょう。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.fcs3httrll4l

下でも書いていますが、weights で回すほうが多分素直なんでしょうね。

while days:
if total_weight + weights[i] > capacity:
total_weight = 0
days -= 1
continue

total_weight += weights[i]
i += 1
if i == len(weights):
return True
Comment on lines +17 to +26
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こう書くなら、個人的にはこう変形した方がわかりやすい気がしています

           while days:
                if i == len(weights):
                    return True
                if total_weight + weights[i] > capacity:
                    total_weight = 0
                    days -= 1
                total_weight += weights[i]
                i += 1
            return False


return False

left = 1
right = sum(weights)
while left < right:
middle = (left + right) // 2
if can_ship_capacity_in_days(middle, days):
right = middle
else:
left = middle + 1

return left
```
思考ログ:
- 問題を読み違えて時間を無駄にしていた(weightsの順序を保つ制約を無視していた)
- 二分探索の探索用変数の名前を横着している、step2以降なんとかする
- 類似の問題を昔解いたのを覚えていた
- あるcapacityにした時、days内で輸送できるか考える
- capacity = sum(weights)とすれば、必ず1日で輸送できる
- 輸送できるcapacityのうち最小のものを探す
- [輸送できない, 輸送できない, ..., 輸送できない, (輸送できる], 輸送できる, ... ,輸送できる]

# Step2

講師役目線でのセルフツッコミポイント:
- weights=[], days=0の時は?

参考にした過去ログなど:
- https://github.com/saagchicken/coding_practice/pull/15
- 探索範囲は1からでなくmax(weights)からでいい
- https://github.com/saagchicken/coding_practice/pull/10
- https://github.com/olsen-blue/Arai60/pull/44
- https://github.com/hroc135/leetcode/pull/42
- goのbinary-searchの実装
- https://github.com/Ryotaro25/leetcode_first60/pull/51
- Makefileについて
- https://github.com/Mike0121/LeetCode/pull/46
- https://github.com/Yoshiki-Iwasa/Arai60/pull/37
- https://github.com/rossy0213/leetcode/pull/26
- https://github.com/goto-untrapped/Arai60/pull/41
- https://github.com/fhiyo/leetcode/pull/45
- https://github.com/fhiyo/leetcode/pull/45/files#r1682470839
- https://github.com/sakupan102/arai60-practice/pull/45
- https://github.com/SuperHotDogCat/coding-interview/pull/27
- https://github.com/SuperHotDogCat/coding-interview/pull/27/files#r1631399685
- 命名はなかなか難しいなと
- 実態を表すよう無理に情報を詰め込むと拗らせるので、そういう場合はなるべくシンプルにして、必要ならコメント補足を心掛ける
- https://github.com/YukiMichishita/LeetCode/pull/10
- bisect_left/right
- bisect_rightを勘違いしていた(等号は含まない)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bisect_right は、「昇順になるように挿入するとしたら可能な範囲の中で一番右の位置」を見つけてきますね。

- https://docs.python.org/ja/3.13/library/bisect.html
> all(elem > x for elem in a[ip : hi]) is true for the right slice.
- https://github.com/shining-ai/leetcode/pull/44
- https://github.com/hayashi-ay/leetcode/pull/55

所要日数を計算する
```python
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
assert days > 0
if not weights:
return 0

def calculate_shipping_days(capacity: int) -> int:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calculate良いですが、わたしならget_days_requiredとかにするかもしれません

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好みかもですが、日数の情報は、キャパの判断材料にしかすぎないので脇役で使いたいという気持ちがありますね。
https://github.com/olsen-blue/Arai60/pull/44/files#diff-4e146417f14c744a10f851601f26cd2cb17b420ff966720e568f6f5679aa475eR120-R123

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同意です。

他の方が書かれていた、所用日数を計算する、という選択肢が頭になかったので書いてみました。

total_weight = 0
days_required = 1
for weight in weights:
if total_weight + weight > capacity:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

このコードの場合、lowの初期値が1でも動きますか?
たぶん、どこかに
if weight>capacity:
return False
を入れておいたほうが堅牢だと思います。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この場合だと日付を求めているので、返すのはinfとかsys.maxintですかね
例外という選択肢もありますが、受け取る側がやや手間ではありますね

total_weight = 0
days_required += 1

total_weight += weight

return days_required

low = max(weights)
high = sum(weights)
while low < high:
candidate_capacity = (low + high) // 2
if calculate_shipping_days(candidate_capacity) <= days:
high = candidate_capacity
else:
low = candidate_capacity + 1

return low
```
思考ログ:

bisect_right(練習)
```python
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
assert days > 0
if not weights:
return 0

def can_ship(capacity: int) -> bool:
total_weight = 0
days_required = 1
for weight in weights:
if total_weight + weight > capacity:
total_weight = 0
days_required += 1

total_weight += weight
Comment on lines +127 to +132
Copy link

@olsen-blue olsen-blue Apr 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if の中に計算式があるのは、なんか変な感じがしました。
ここの書き方は下記のように改善できる気がしました。
https://github.com/hayashi-ay/leetcode/pull/55/files#diff-4e146417f14c744a10f851601f26cd2cb17b420ff966720e568f6f5679aa475eR97-R101

total_weight は思考の中心にあるコップみたいなものだと思うんですよね。もうちょい上のほうに書いてあげたいです。
https://github.com/saagchicken/coding_practice/pull/10/files#r1995442298

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私もそのイメージでした。

空のコップ(total_weight)を用意して、水(weight)を入れていく、ただ溢れそうになったら(if total_weight + weight > capacity:)新しいコップを用意して(total_weight = 0)、使用したコップの数を記録しておくカウンターを1進める(days_required += 1

頂いたリンクも事前に確認していたのですが、こちらは、

コップに水を入れたら溢れちゃったので、新しいコップを用意して今回の分量の水を入れて再開する

という感じで、個人的には前者の方が好みでした。
ただ私の感覚がおかしいのかもしれません。

Copy link

@olsen-blue olsen-blue Apr 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この辺りでも同じ感情を持ちました
Fuminiton/LeetCode#30 (comment)
Fuminiton/LeetCode#30 (comment)


return days_required <= days

return bisect.bisect_right(
range(sum(weights) + 1),
False,
lo=max(weights),
hi=sum(weights) + 1,
key=can_ship
)
```
思考ログ:
- 今回の課題で敢えて使うこともないが、bisect_rightの練習で書いてみた
- 関数名、```can_ship```くらいでいい気もするので少し変更

# Step3

かかった時間:5min

```python
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
assert days > 0
if not weights:
return 0

def can_ship(capacity: int) -> bool:
total_weight = 0
days_required = 1
for weight in weights:
if weight > capacity:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

そうですよね、bisectでrangeをつかうならこの例外処理が必要になると思います

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lo= を書いているので、なくても動くかとは思いますが、しかし書いたほうが読みやすいでしょうね。後々変更が入ったときにバグの原因にもなりそうですし。

return False

if total_weight + weight > capacity:
total_weight = 0
days_required += 1

total_weight += weight

return days_required <= days
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私はdays requiredがdaysを超えた時点で弾きたくなります


return bisect.bisect_left(
range(sum(weights)),
True,
key=can_ship,
lo=max(weights),
hi=sum(weights)
)
```
思考ログ:
- ```weight > capacity```の早期リターンを追加

# Step4

```python
```
思考ログ: