Solved Arai60/1011. Capacity To Ship Packages Within D Days#44
Solved Arai60/1011. Capacity To Ship Packages Within D Days#44
Conversation
| def shipWithinDays(self, weights: List[int], days: int) -> int: | ||
| if days <= 0: | ||
| return -1 | ||
| if not weights: |
There was a problem hiding this comment.
おそらくL128のmaxでエラーを出さないために入れていると思うのですが、maxにdefault引数を指定してこれは消してしまっても良いと思います。
https://docs.python.org/ja/3.13/library/functions.html#max
| daily_load = weight | ||
| return required_days <= days | ||
|
|
||
| return bisect_left( |
There was a problem hiding this comment.
面白い書き方だと思いました。
個人的にはindexという一見capacityとは対応していなさそうに見えるものを返すのは一瞬不思議に思いましたが、慣れればそうでもないのかもしれません。
sequence = range(max(weights), sum(weights) + 1)
index = bisect_left(sequence, True, key=canShipWithCapacity)
return sequence[index]このようにしてしまう選択肢もあると思いました。
nanae772
left a comment
There was a problem hiding this comment.
お疲れ様です、思考やコードが丁寧に書かれていてとても読みやすかったです。
| min_capacity = max(max(weights), sum(weights) // days) | ||
| daily_capacity = min_capacity | ||
| days_left = days | ||
| while True: |
There was a problem hiding this comment.
min_capacityはループの中で必ず1ずつ増えていくので自分ならforループにするかなと思いました
| return min_capacity | ||
| days_left = days | ||
| min_capacity += 1 | ||
| daily_capacity = min_capacity |
There was a problem hiding this comment.
23行目と同様にfor weight in weights:の前に書くかなと思いました。
| daily_capacity -= weight | ||
| if days_left > 0: | ||
| return min_capacity | ||
| days_left = days |
There was a problem hiding this comment.
自分はこれはforループの前の初期化のイメージなのでfor weight in weights:の前に書くかなと思いました。
そうすると12行目の代入も省けそうです
| ```python | ||
| class Solution: | ||
| def shipWithinDays(self, weights: List[int], days: int) -> int: | ||
| min_capacity = max(max(weights), sum(weights) // days) |
There was a problem hiding this comment.
私はぱっと見だと分からず少し思考が必要だったので、単にmax(weights)という明らかに最小だと分かるものにしておくのもよいかもしれません。
ただ、可能な限り大きい値にしておけばループの回数も減るのでその辺はトレードオフになりそうです。
There was a problem hiding this comment.
常にmax(weights)>= sum(weights) // daysが成立するので、いずれにせよ冗長だと思います。
|
|
||
| - max(weights)とsum(weights)の間に答えがあると考えられる(!)のでこれを用いて二分探索する方法がある | ||
| - これがどれだけ速いのかをよく理解できていない | ||
| - 元々期待値として線形に船の容量を上げるとどうなるのか? |
There was a problem hiding this comment.
探索の範囲を具体的に考えてみるとどうでしょうか。例えば長さ10000の範囲だとして、線形探索では最悪何ステップかかって二分探索だと最悪何ステップになるか、という具体例を考えてみるとどれだけ速くなるかが定量的につかめるかなと思います。
| - これがどれだけ速いのかをよく理解できていない | ||
| - 元々期待値として線形に船の容量を上げるとどうなるのか? | ||
| - bisect_leftの引数に自分で定義した関数を渡す方法 | ||
| - https://github.com/tokuhirat/LeetCode/pull/44/files#diff-06f87195f0dc2635b3c326a3257c212b916a27bd5f47afbf0368d37831b513a3R29 |
| - https://github.com/Fuminiton/LeetCode/pull/44/files | ||
| - https://github.com/nittoco/leetcode/pull/47/files | ||
| - いつも思うがなぜ皆同じような解法になっているんだろうか?自分だけ何かを理解できていないような気分 | ||
| - 取りあえず今回のような範囲を思いつきにくい場合でも二分探索を軸に考えるのは一般的と理解しておく |
There was a problem hiding this comment.
イメージとしてはどっかでTrue/Falseが入れ替わる境界があるときに二分探索が使えそうだな~という発想になるのかなと思っています。
今回のケースで言うと「days日間でcapacityの船で全ての積み荷を輸送できるか?」というブール値がcapacityを増やしていくと
False, False, ..., False, True, True, ...
と明確に「ここから下は全てFalse」「ここから上は全てTrue」という境界があるはずなので二分探索できるなという気持ちですかね。
| left = max(weights) | ||
| right = sum(weights) |
There was a problem hiding this comment.
left, rightがどのような不変条件を満たしているかを言語化してみて変数名をつけるとより分かりやすくなるのかなと思いました。
二分探索を考える際、以下の議論なども参考になるかもしれません。
KentaroJay/Leetcode#18 (comment)
potrue/leetcode#41 (comment)
| if days <= 0: | ||
| return -1 | ||
|
|
||
| def canShipWithCapacity(capacity: int) -> bool: |
There was a problem hiding this comment.
inner function の関数名は、 lower_snake で書くことが多いと思います。 LeetCode が指定している関数名は仕方ないと思います。
参考までにスタイルガイドへのリンクを貼ります。
https://peps.python.org/pep-0008/#function-and-variable-names
Function names should be lowercase, with words separated by underscores as necessary to improve readability.
https://google.github.io/styleguide/pyguide.html#316-naming
function_name
上記のスタイルガイドは唯一絶対のルールではなく、複数あるスタイルガイドの一つに過ぎないということを念頭に置くことをお勧めします。また、所属するチームにより何が良いとされているかは変わります。自分の中で良い書き方の基準を持ちつつ、チームの平均的な書き方で書くことをお勧めいたします。
問題文:https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/description/