-
Notifications
You must be signed in to change notification settings - Fork 0
11. Container With Most Water #8
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,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) { | ||
| 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 { | ||
|
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. この 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) | ||
|
|
||
| 左右を動かしていく方法がある。 | ||
| まずは日本語で構造を整理する。 | ||
|
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. 念のため確認させてください。なぜこの方法で正しく動くか説明してみていただけますか? |
||
|
|
||
| - 左端と右端を決める。 | ||
| - 右端の高さが左端より大きい場合、左端を動かす。 | ||
| - 右端の高さが左端より小さい場合、右端を動かす。 | ||
| - このとき、面積を計算して、最大値を更新する。 | ||
| - 左端と右端が重なるまで繰り返す。 | ||
|
|
||
| 実装してみる。 | ||
| ### 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 | ||
|
|
||
| * | ||
| $$ | ||
| 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
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. 全組合せを見るのであれば、よくあるシンプルな二重ループで見ていくのがわかりやすそうです。j を右端から見ていくことと if 文での判定を入れることでいくつかの area の計算をスキップできる嬉しさや途中での打ち切りができる嬉しさがあるということかと思いますが、その嬉しさよりも可読性がより優先度が高いかなと個人的には思います。
Suggested change
|
||||||||||||||||
| { | ||||||||||||||||
| if (height[j] >= height[i]) { | ||||||||||||||||
| current_max_area = max(current_max_area, (j - i) * height[i]); | ||||||||||||||||
| break ; | ||||||||||||||||
|
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. ここの 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); | ||||||||||||||||
| } | ||||||||||||||||
| 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]); | ||
|
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. 細かいですが、 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. こちら僕も同意です |
||
| 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
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. 先に 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); | ||
| } | ||
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.
ネストが深く、やや読みにくく感じました。条件の真偽を逆にして、 continue したほうが読みやすくなると思います。