-
Notifications
You must be signed in to change notification settings - Fork 0
1011. Capacity To Ship Packages Within D Days #46
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,54 @@ | ||
| /* | ||
| ・概要 | ||
| 自力解放。10分ほどで実装して、10分くらいでTLE | ||
|
|
||
| ・解法 | ||
| 重さを固定して、毎回weightsを操作して条件にあうか確かめる。 | ||
| 重さの候補としては、weightsの最大値をmaxWとすると、maxW <= 候補 <= maxW * weightsの要素数 | ||
| となるので、この範囲で探していき、条件通り指定日以下になるかみていく。 | ||
|
|
||
| ・計算量 | ||
| // O(m * n), m: 最大値*weights, n: weightsの要素数 | ||
| // 今回の条件的には mが最大で5 * 10 ^ 4 * 500 なので大きく見積もっても10 ^ 8 | ||
|
|
||
| ・所感 | ||
| ギリギリまにあうかなとおもったけど、TLEになってしまい、改善できそうなところを考えると線形走査しているmaxW <= 候補 <= maxW * weightsの要素数の部分を二分探索すればlognに計算量を減らせるのでそちらは次の解法でためす。 | ||
|
|
||
| */ | ||
|
|
||
| public class solution1_1 { | ||
| class Solution { | ||
| // weightsの最大値を見つける。 | ||
| // 最大値から最大値*weightsの数の値だけ繰り返し処理をする | ||
| // 繰り返し処理:capを固定してweightsを走査して、指定日数以下で返せるかをみていく。 | ||
| // O(m * n), m: 最大値*weights, n: weightsの要素数 | ||
| // mは制約から最大で5 * 10 ^ 4 * 500 = 10 ^ 8 | ||
|
|
||
| public int shipWithinDays(int[] weights, int days) { | ||
| int maxWeight = 0; | ||
| for (int weight : weights) { | ||
| maxWeight = Math.max(maxWeight, weight); | ||
| } | ||
|
|
||
| for (int capacity = maxWeight; capacity <= maxWeight * weights.length; capacity++) { | ||
| int currentSumWeights = 0; | ||
| int currentDays = 1; | ||
| for (int weight : weights) { | ||
| if (currentSumWeights + weight <= capacity) { | ||
| currentSumWeights += weight; | ||
| } else { | ||
| currentSumWeights = weight; | ||
| currentDays++; | ||
| if (days < currentDays) { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if (currentDays <= days) { | ||
| return capacity; | ||
| } | ||
| } | ||
| return -1; // ここは想定外なのでエラーハンドリングなどは相談 | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| ・概要 | ||
| solution1_1について走査部分を二分探索にして計算量を改善したもの。 | ||
| 15分くらいでAC | ||
|
|
||
| ・解法 | ||
| 走査部分について | ||
| 1, 不変条件 | ||
| 見つけたいもの:条件を満たす最小のcapacity | ||
| left: これを以下の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. これ未満のCapacityでは条件をみたさない。ですね |
||
| right:これ以上のCapacityで条件をみたす。 | ||
| 2, 更新処理 | ||
| leftとrightの間の値candidateをみていく。条件(かかる日数がdays以下)を満たすの時は、 | ||
| 定義より、right = candidate | ||
| 逆に条件を満たさない時は、left = candidate + 1; | ||
| 3, 終了条件 | ||
| 定義より、leftとrightが一致したところが見つけたいものと同じになるのでleft == right | ||
|
|
||
| ・計算量 | ||
| // O(log(m) * n), m: 最大値*n, n: weightsの要素数 | ||
| // m = 500n = 500 * 5 * 10 ^ 4 = 25 * 10 ^ 6 → 2 * 10 ^ 7 | ||
| // nlog(m) = 500 * log(2 * 10 ^ 7) = 500 * 7 * log(20) = 3500 * log (20) = 3500 * (2log(2) + log(5)) = 3500 * (2 + 2.3) = 3500 * 5 = 175000 = 2 * 10 ^ 5 | ||
| // 大体Javaが1sで10^7くらい処理ができるとすると、2 * 10 ^ 5 / 10 ^ 7 = 2 / 10 ^ 2 = 20msくらいで完了しそう | ||
|
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. 自分はJavaにそこまで詳しくないですが、1sで10^7くらい、はやや過小評価に感じました。 JITコンパイラ特有のスロースタート的な特性などもあると思いますが、このくらいの繰り返しが明確で単調、インスタンス生成も特にない処理なら、JIT最適化後は効率的に機械語に翻訳され1sに10^8-10^9くらい行くかなと思いました。(CPUのクロック周波数が数GHz程度という前提のもと) 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. ベンチマークサイトによると Java は C に比べて 3~4 倍程度遅いようです。
1s に 107~108 くらいで見積もるとよいと思いました。 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. 私も 10^8-10^9 くらいで見積もりそうですが、しかし、一般にソフトウェアの速度は保守的に見積もったほうがいいんですよね。(予想外に速くて困ることはあまりないが逆は困ることがあるので。)
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. ありがとうございます。そうですね、少し幅を 10^7~10^8 くらいで認識します。 |
||
|
|
||
| */ | ||
|
|
||
| public class solution1_2 { | ||
| public int shipWithinDays(int[] weights, int days) { | ||
| int maxWeight = 0; | ||
| for (int weight : weights) { | ||
| maxWeight = Math.max(maxWeight, weight); | ||
| } | ||
| int left = maxWeight; | ||
| int right = maxWeight * weights.length; | ||
| while (left < right) { | ||
| int candidateCapacity = left + (right - left) / 2; | ||
| int currentSumWeights = 0; | ||
| int currentDays = 1; | ||
|
|
||
| // この辺りは関数にしてもいいかも | ||
| for (int weight : weights) { | ||
| if (currentSumWeights + weight <= candidateCapacity) { | ||
| currentSumWeights += weight; | ||
| } else { | ||
| currentSumWeights = weight; | ||
| currentDays++; | ||
| if (days < currentDays) { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| if (currentDays <= days) { | ||
| right = candidateCapacity; | ||
| } else { | ||
| left = candidateCapacity + 1; | ||
| } | ||
| } | ||
| return left; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| /* | ||
| ・概要 | ||
| 他の人のPRなどを参考にしたもの。 | ||
| https://github.com/garunitule/coding_practice/pull/44/files | ||
| 変数のつけかたが具体的でいい。自分はsolution1_2で二分探索のところを安易にleft, rightと置いていたが確かに処理フロー的に不自然なのでコンテキストにあった名前にしたい | ||
| ex) left = maxInvalidCapacity, right = minValidCapacity とか? もっと簡単なら minCapacity, maxCapacityとかでもよいかも? | ||
| あと、solution1_2でも思った通り、条件にあうかの判定部分を関数化しているのでこれもよさそう | ||
|
|
||
| https://github.com/h1rosaka/arai60/pull/46/files | ||
| 走査の最大値が配列の合計値という違いがある(たしかにこれはそう)。終了条件と定義からleft,rightが隣り合っている時となっている。 | ||
|
|
||
| https://github.com/hayashi-ay/leetcode/pull/55/files#diff-4e146417f14c744a10f851601f26cd2cb17b420ff966720e568f6f5679aa475eR36-R58 | ||
| の2ndはきれい | ||
| */ | ||
|
|
||
| public class solution2_1 { | ||
| public int shipWithinDays(int[] weights, int days) { | ||
| int maxWeight = 0; | ||
| int sumWeight = 0; | ||
| for (int weight : weights) { | ||
| maxWeight = Math.max(maxWeight, weight); | ||
| sumWeight += weight; | ||
| } | ||
| int minCapacity = maxWeight; | ||
| int maxCapacity = sumWeight; | ||
| while (minCapacity < maxCapacity) { | ||
| int midCapacity = minCapacity + (maxCapacity - minCapacity) / 2; | ||
| if (canShipWeight(weights, days, midCapacity)) { | ||
| maxCapacity = midCapacity; | ||
| } else { | ||
| minCapacity = midCapacity + 1; | ||
| } | ||
| } | ||
| return minCapacity; | ||
| } | ||
|
|
||
| private boolean canShipWeight(int[] weights, int days, int capacity) { | ||
| int currentSumWeight = 0; | ||
| int currentDays = 1; | ||
| for (int weight : weights) { | ||
| if (currentSumWeight + weight <= capacity) { | ||
| currentSumWeight += weight; | ||
| } else { | ||
| currentSumWeight = weight; | ||
| currentDays++; | ||
| } | ||
| if (days < currentDays) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| } |
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.
個人的にはここのif-elseはif-continueで書きたいと感じました。
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.
ありがとうございます。たしかにネストへるしいいですね