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
109 changes: 109 additions & 0 deletions 1011/1011.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
## 何も見ずに解いてみる

```cpp
class Solution {
public:
int shipWithinDays(vector<int>& weights, int days) {
int capacity_min = *max_element(weights.begin(), weights.end());
int capacity_max = accumulate(weights.begin(), weights.end(), 0);
Copy link

Choose a reason for hiding this comment

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

ただの感想なんですが、C++ってsum()がないんですね

Copy link
Owner Author

Choose a reason for hiding this comment

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

最大値を探すものはstd::max_elementというのがありますが、sumは直接的なものはないようです。

while (capacity_min < capacity_max) {
int capacity_mid = capacity_min + (capacity_max - capacity_min) / 2;
if (can_ship(weights, days, capacity_mid)) {
capacity_max = capacity_mid;
}
else {
capacity_min = capacity_mid + 1;
}
}
return capacity_min;
}
private:
bool can_ship(vector<int>& weights, int days, int capacity) {
Copy link

Choose a reason for hiding this comment

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

複合型で、関数の内部で変更されない変数の型には const を付けることをおすすめします。ついていないと、読み手が、変数が関数内で変更されることを前提に読んでしまい、混乱してしまう場合があると思います。

Copy link

Choose a reason for hiding this comment

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

C++ では関数名を lower_snake とするのは、あまり見ないように思います。 UpperCamel をよく見かけます。

参考までにスタイルガイドへのリンクを貼ります。

https://google.github.io/styleguide/cppguide.html#Function_Names

Ordinarily, functions follow PascalCase: start with a capital letter and have a capital letter for each new word.

上記のスタイルガイドは唯一絶対のルールではなく、複数あるスタイルガイドの一つに過ぎないということを念頭に置くことをお勧めします。また、所属するチームにより何が良いとされているかは変わります。自分の中で良い書き方の基準を持ちつつ、チームの平均的な書き方で書くことをお勧めいたします。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。leetcodeのテンプレートに設定されているデフォルトに合わせてlowerCamelで書いてみます。

int current_day = 1;
int load = 0;
for (int weight : weights) {
if (load + weight <= capacity) {
load += weight;
}

Choose a reason for hiding this comment

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

continue して else のインデントを下げたいと思いました。

else {
if (weight > capacity) {

Choose a reason for hiding this comment

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

このチェックは for 文の先頭にあっても良いかなと思いました。

Copy link
Owner Author

Choose a reason for hiding this comment

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

迷いました。実世界で手作業で船に積んでいくとしたらどういう順番でチェックするだろうか、ということを考えてここに置いてみましたが、最初に置いてもいいと思います。
そもそも下限を荷物の最大重量から始めているので省くのも選択肢に入るかもしれません。

Choose a reason for hiding this comment

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

そもそも下限を荷物の最大重量から始めている

確かにそうですね。省いても良いと思います。

return false;
}
current_day += 1;
if (current_day > days) {
return false;
}
load = weight;
}
}
return true;
}
};
```

## 他の人のコードを見てみる

https://github.com/tokuhirat/LeetCode/pull/44/files
https://github.com/ryosuketc/leetcode_arai60/pull/33/files
https://github.com/Ryotaro25/leetcode_first60/pull/51/files
https://github.com/goto-untrapped/Arai60/pull/41/files

## 最終コード

weightsとdaysをキャプチャしたいと思ったのでラムダ式で書いてみました。

```cpp
if (++current_day > days) {
// ...
}
```
の部分は
```cpp
++current_day;
if (current_day > days) {
// ...
}
```
の方が一般的なんですかね?調べた感じどっちも結構ありそうでした。

```cpp
class Solution {
public:
int shipWithinDays(vector<int>& weights, int days) {
auto can_ship = [&weights, days](int capacity) -> bool {
Copy link

Choose a reason for hiding this comment

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

数行を超えるラムダ関数は、ネストが深くなったり、ラムダ関数の前後を追う際に目の移動量が多くなったりと、読みにくく感じます。メンバ関数にくくりだしたほうが良いと思います。

並列計算フレームワークに渡すロジックを記述する際や、 UI のイベントハンドラーを大量に書かなければならない場合等、ラムダ関数にせざるを得ない場合もあるとは思います。

int current_day = 1;

Choose a reason for hiding this comment

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

currentというよりは所要日数の方が実態に近いかと思いました。required_daysなどどうでしょうか。

Copy link
Owner Author

Choose a reason for hiding this comment

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

そちらの方がわかりやすいかもしれませんね。実際に積んでいく状況をイメージして書くのと、もしも積んでいったらどれぐらい必要だろうか、という計算をするイメージで書くので変わってくるかもしれません。(自分は前者のイメージでした)

int load = 0;
for (int weight : weights) {
if (load + weight <= capacity) {
load += weight;

Choose a reason for hiding this comment

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

continue して else のネストをなくしたい気がします (全体的にネストが深いので)。

}
else {
if (weight > capacity) {
return false;
Comment on lines +81 to +82

Choose a reason for hiding this comment

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

can_ship を独立の関数と考えるとこの処理は確かにしたいのですが、low を weights の max としているのでなくても動きますね。

}
if (++current_day > days) {
Copy link

Choose a reason for hiding this comment

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

式の中に副作用があると同時に色々やっていてわかりにくいという意見もありそうですね(練習マニュアルにもあった気はします)
これくらいならそんなに混乱しないかもしれないですが

return false;
}
load = weight;
}
}
return true;
};

Choose a reason for hiding this comment

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

冒頭に書かれたコードの方が読みやすかったです。少なくともここに空行があると良いかなと思います。

int low = *max_element(weights.begin(), weights.end());
int high = accumulate(weights.begin(), weights.end(), 0);

Choose a reason for hiding this comment

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

c++17から reduce というものがあるそうです。
https://cpprefjp.github.io/reference/numeric/reduce.html

Copy link
Owner Author

Choose a reason for hiding this comment

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

どっちでもいいかなと思ってたのですが、色々見てみると今回はreduceのほうが良さそうですね!ありがとうございます。

while (low < high) {
int mid = low + (high - low) / 2;
if (can_ship(mid)) {
high = mid;
}
else {
low = mid + 1;
}
}
return low;
}
};
```

`current_day`を`0`で初期化してしまい一敗・・・
`1`から始める方が現実世界の考え方には即しているような気がするのでこのままにします