Skip to content
Open
Show file tree
Hide file tree
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
Binary file added 11_container_with_most_water/a.out
Binary file not shown.
105 changes: 105 additions & 0 deletions 11_container_with_most_water/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# 11. Container With Most Water

https://leetcode.com/problems/container-with-most-water/description/

問題の概要。
二次元の水槽の中に入れれる最大の水の面積を答えよ。って問題。

まず選択肢は、 $\binom{N}{2} = O(N^2)$ 個存在する。

2つのうち、1つを固定する。
それをi番目とする。

もう片方をj番目とする。
そのとき、横幅は、

$$ | i - j | $$

高さは、
$$ \min(height[i], height[j]) $$

そのときの面積は、
$$ | i - j | \cdot \min(height[i], height[j]) $$

とりあえず、見るべきは反対側の初めて、
$$ hegiht[j] \geqq height[i] $$
となる $ j $ (つまり、最大の$ j $) を見つけなければいけない。
それ以上内側は見る必要がない。

また、現在見ている中で最大の面積より低くなる場合は探索する必要はない。
例えば、

$$ N = 5, i = 2 , hegiht[i] = 4, maxS = 100$$
のとき、このときの最大値は高々、12なので、$ j $ を探索する必要はない。

## Comments

### step1
```c
int maxArea(int* height, int heightSize)
{
int current_max_area = 0;
for (int i = 0; i < heightSize; i++)
{
if ((heightSize - i) * height[i] >= current_max_area) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ネストが深く、やや読みにくく感じました。条件の真偽を逆にして、 continue したほうが読みやすくなると思います。

for (int j = heightSize - 1; j > i; j--)
{
if (height[j] >= height[i]) {
current_max_area = max(current_max_area, (j - i) * height[i]);
break ;
}
else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

この else 不要ですかね。

current_max_area = max(current_max_area, (j - i) * height[j]);
}
}
}
}
return (current_max_area);
}
```

実装はできたけど、計算量はもうちょい改善できそう。
$時間計算量 = O ( N^2 ) $
どうしたら改善できるか。
他の人のコードを見てみる。

* [shintaroyoshida20の11番](https://github.com/shintaroyoshida20/leetcode/pull/34/files)
* [texthonda28の11番](https://github.com/thonda28/leetcode/pull/16)

左右を動かしていく方法がある。
まずは日本語で構造を整理する。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

念のため確認させてください。なぜこの方法で正しく動くか説明してみていただけますか?


- 左端と右端を決める。
- 右端の高さが左端より大きい場合、左端を動かす。
- 右端の高さが左端より小さい場合、右端を動かす。
- このとき、面積を計算して、最大値を更新する。
- 左端と右端が重なるまで繰り返す。

実装してみる。
### step2

```c
int maxArea(int* height, int heightSize)
{
int left = 0;
int right = heightSize - 1;
int current_max_area = (right - left) * min(height[left], height[right]);
while (left < right)
{
if (height[left] < height[right]) {
left++;
}
else {
right--;
}
current_max_area = max (current_max_area, (right - left) * min(height[left], height[right]));
}
return (current_max_area);
}
```
* だいぶきれいに実装できた。

### step3

*
$$
42 changes: 42 additions & 0 deletions 11_container_with_most_water/step1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
int max(int a, int b)
{
if (a > b) {
return (a);
}
else {
return (b);
}
}

int maxArea(int* height, int heightSize)
{
int current_max_area = 0;
for (int i = 0; i < heightSize; i++)
{
if ((heightSize - i) * height[i] >= current_max_area) {
for (int j = heightSize - 1; j > i; j--)
Comment on lines +14 to +17
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

全組合せを見るのであれば、よくあるシンプルな二重ループで見ていくのがわかりやすそうです。j を右端から見ていくことと if 文での判定を入れることでいくつかの area の計算をスキップできる嬉しさや途中での打ち切りができる嬉しさがあるということかと思いますが、その嬉しさよりも可読性がより優先度が高いかなと個人的には思います。

Suggested change
for (int i = 0; i < heightSize; i++)
{
if ((heightSize - i) * height[i] >= current_max_area) {
for (int j = heightSize - 1; j > i; j--)
for (int i = 0; i < heightSize; i++)
{
for (int j = i + 1; j < heightSize; j++)

{
if (height[j] >= height[i]) {
current_max_area = max(current_max_area, (j - i) * height[i]);
break ;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ここの break は memo.md に思考が書いてあったため意味がわかりましたが、コードだけを見たときにはコメント無しでは読み手が意図を汲み取るのに苦労しそうです。(ぱっと見でなぜこちらの分岐だけ打ち切っていいのかわかりませんでした)

}
else {
current_max_area = max(current_max_area, (j - i) * height[j]);
}
}
}
}
return (current_max_area);
}

#include <stdio.h>

int main(void)
{
int height[] = {1,8,6,2,5,4,8,3,7};
int heightSize = 9;
// int height[] = {10,1,9,11,1,1,1,1,10};
// int heightSize = 9;
printf("%i\n", maxArea(height, heightSize));
return (0);
}
49 changes: 49 additions & 0 deletions 11_container_with_most_water/step2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
int max(int a, int b)
{
if (a > b) {
return (a);
}
else {
return (b);
}
}

int min(int a, int b)
{
if (a < b) {
return (a);
}
else {
return (b);
}
}

int maxArea(int* height, int heightSize)
{
int left = 0;
int right = heightSize - 1;
int current_max_area = (right - left) * min(height[left], height[right]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

細かいですが、 current の情報量が少ないため、
max_areaでも十分意味が伝わると思いました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちら僕も同意です

while (left < right)
{
if (height[left] < height[right]) {
left++;
}
else {
right--;
}
current_max_area = max (current_max_area, (right - left) * min(height[left], height[right]));
}
Comment on lines +26 to +35
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

先に left, right を移動させてから計算を行うのが個人的には違和感がありました。おそらく初期化でした計算を再度したくなかったという意図ですかね?

ループは「今回の処理、次回の準備」のような流れで自然言語で説明できるコードが個人的にはわかりやすいと感じます。

return (current_max_area);
}

#include <stdio.h>

int main(void)
{
int height[] = {1,8,6,2,5,4,8,3,7};
int heightSize = 9;
// int height[] = {10,1,9,11,1,1,1,1,10};
// int heightSize = 9;
printf("%i\n", maxArea(height, heightSize));
return (0);
}
Empty file.