-
Notifications
You must be signed in to change notification settings - Fork 0
Solved: 1011. Capacity To Ship Packages Within D Days #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| ## 取り組み方 | ||
| - step1: 5分以内に空で書いてAcceptedされるまで解く + テストケースと関連する知識を連想してみる | ||
| - step2: 他の方の記録を読んで連想すべき知識や実装を把握した上で、前提を置いた状態で最適な手法を選択し実装する | ||
| - step3: 10分以内に1回もエラーを出さずに3回連続で解く | ||
|
|
||
| ## step1 | ||
| 1日に取り込める最小のキャパを求める。 | ||
| キャパとして考えられるmax(weights)~sum(weights)の中で最初に満たす値が最小のキャパ。 | ||
| これを二分探索で求める。 | ||
|
|
||
| キャパとして可能かどうかの判定は、以下。 | ||
|
|
||
| 1. ベルトコンベアの先から貸物の重さを足していく | ||
| 2. 重さの合計がキャパを超えるかみる | ||
| 3. 超えたら、一つ前までの貨物で重さをリセットし、日を進める | ||
| 4. 1~3.をループしてすべての貨物を見終わったときに、所要日数がdays以内ならオッケー | ||
|
|
||
| 時間計算量は、O(weights.length * log(max(weights) * weights.length)) なので数秒もかからない見込み。 | ||
|
|
||
| bisect_leftを使うか迷ったが、max(weights)~sum(weights)の配列を作る方法しか思いつかなかったので、 | ||
| 余計に大きな配列を作らなくて良いという観点で自前の二分探索で書く方が良いかと思った。 | ||
|
|
||
| ### bisect_leftを使わない | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def shipWithinDays(self, weights: List[int], days: int) -> int: | ||
| def can_ship(capacity: int) -> bool: | ||
| processing_days = 1 | ||
| loaded = 0 | ||
| for weight in weights: | ||
| if weight + loaded > capacity: | ||
| processing_days += 1 | ||
| loaded = 0 | ||
| loaded += weight | ||
|
|
||
| return processing_days <= days | ||
|
|
||
| maybe_first_can_ship_capacity = max(weights) | ||
| can_ship_capacity = sum(weights) | ||
| while maybe_first_can_ship_capacity < can_ship_capacity: | ||
| mid = (maybe_first_can_ship_capacity + can_ship_capacity) // 2 | ||
| if can_ship(mid): | ||
| can_ship_capacity = mid | ||
| else: | ||
| maybe_first_can_ship_capacity = mid + 1 | ||
|
|
||
| return maybe_first_can_ship_capacity | ||
| ``` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FFF?????TTTTがあって、maybe_first_can_ship_capacityは最初の?で、can_ship_capacityは最初のTでしょうか。 それと変数名的にmaybe_first_can_ship_capacityが帰ってくるのは怖くなりました。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
maybe_first_can_ship_capacityが最初のTか、Fで、can_ship_capacityが常にTになる値のイメージです。 ループの打ち切りがmaybe_first_can_ship_capacity==can_ship_capacityなので伝わるだろうと思いmaybeの方を返すようにしましたが、おっしゃる通りmaybeな値が返ってくるのは良くないですね There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
これは伝わると思います。 |
||
|
|
||
| ### bisect_leftを使う | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def shipWithinDays(self, weights: List[int], days: int) -> int: | ||
| def can_ship(capacity: int) -> bool: | ||
| processing_days = 1 | ||
| loaded = 0 | ||
| for weight in weights: | ||
| if weight + loaded > capacity: | ||
| processing_days += 1 | ||
| loaded = 0 | ||
| loaded += weight | ||
|
|
||
| return processing_days <= days | ||
|
|
||
| maybe_min_capacity = max(weights) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. upper_limit,lower_limitとかでしょうか
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます。 |
||
| maybe_max_capacity = sum(weights) | ||
| candidates= range(maybe_min_capacity, maybe_max_capacity + 1) | ||
| min_capacity_index = bisect_left(candidates, True, key=can_ship) | ||
| return candidates[min_capacity_index] | ||
| ``` | ||
|
|
||
| ## step2 | ||
| ### 読んだ | ||
| - https://github.com/fuga-98/arai60/pull/44/files | ||
| - https://github.com/fhiyo/leetcode/pull/45/files | ||
| - https://github.com/sakupan102/arai60-practice/pull/45/files | ||
| - https://github.com/nittoco/leetcode/pull/47/files | ||
| - https://github.com/olsen-blue/Arai60/pull/44/files | ||
| - https://github.com/hroc135/leetcode/pull/42/files | ||
|
|
||
| ### 感想 | ||
| - daysが0以下は早期リターンすべきだった | ||
| - 変数名が冗長すぎるかもしれない | ||
| - rangeでリストが作られると思っていたが、実際に作られるのはstartとstop地点、ステップと長さを持ったrange objectらしい | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. リンクの共有ありがとうございます。 |
||
| - ので、自分がstep1時に考えていた「bisect_leftを使うか迷ったが、max(weights)~sum(weights)の配列を作る方法しか思いつかなかった」は杞憂だった | ||
| - 必要になった時点で初めて計算するという遅延評価というものらしい | ||
| - generatorとかiteratorも同じか | ||
| - `range(sum(weights) + 1)`を与えて、`lo=max(weights)`とすればindexではなくて、min_capacityそのものを探せて綺麗な実装だと思った | ||
|
|
||
| https://github.com/python/cpython/blob/9ad0c7b0f14c5fcda6bfae6692c88abb95502d38/Objects/rangeobject.c#L68 | ||
| > obj->start = start; | ||
| > obj->stop = stop; | ||
| > obj->step = step; | ||
| > obj->length = length; | ||
|
|
||
| 実際に中身を見てみた | ||
|
|
||
| ```py | ||
| >>> start = 0 | ||
| >>> end = 50000000 + 1 | ||
| >>> range_object = range(start, end + 1) | ||
| >>> list_object = list(range(start, end + 1)) | ||
| >>> import sys | ||
| >>> print(f"range object: {sys.getsizeof(range_object)} bytes") | ||
| range object: 48 bytes | ||
| >>> print(f"list object: {sys.getsizeof(list_object)} bytes") | ||
| list object: 400000072 bytes | ||
| ``` | ||
|
|
||
| ```py | ||
| class Solution: | ||
| def shipWithinDays(self, weights: List[int], days: int) -> int: | ||
| def can_ship(capacity: int) -> bool: | ||
| processing_days = 1 | ||
| loaded = 0 | ||
| for w in weights: | ||
| if w + loaded > capacity: | ||
| processing_days += 1 | ||
| loaded = 0 # reset | ||
| loaded += w | ||
| return processing_days <= days | ||
|
|
||
| if days < 1: | ||
| raise ValueError("days must be greater than 1.") | ||
|
|
||
| min_capacity = bisect_left( | ||
| range(sum(weights) + 1), | ||
| True, | ||
| lo=max(weights), | ||
| key=can_ship) | ||
| return min_capacity | ||
| ``` | ||
|
|
||
| ### step3 | ||
| ```py | ||
| class Solution: | ||
| def shipWithinDays(self, weights: List[int], days: int) -> int: | ||
| def can_ship_within_days(capacity: int) -> bool: | ||
| task_duration_days = 1 | ||
| loaded = 0 | ||
|
|
||
| for w in weights: | ||
| if w + loaded > capacity: | ||
| task_duration_days += 1 | ||
| loaded = 0 # reset | ||
| loaded += w | ||
|
|
||
| return task_duration_days <= days | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. task_duration_daysがdaysを超えたときにreturn Falseしてもよいですね
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. レビューありがとうございます。 これ気付けてなかったです。 |
||
|
|
||
| min_capacity_candidates = range(sum(weights)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 答えとしてあり得る最大値は sum(weights) なので
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. レビューありがとうございます。 |
||
| return bisect_left( | ||
| min_capacity_candidates, | ||
| True, | ||
| lo=max(weights), | ||
| key=can_ship_within_days | ||
| ) | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe_first_can_ship_capacity という変数名からは「おそらく最初(の船?)は積載量を積載可能だろう」というニュアンスに感じました。表現したい内容とずれているように思います。 maybe_min_shippable_capacity はいかがでしょうか?これもやや微妙ではありますが…。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
レビューありがとうございます。
maybe_min_shippable_capacityの方が適切ですね。
left, rightより良い変数がないかはもう少し考えるべきでした。