-
Notifications
You must be signed in to change notification settings - Fork 0
84. Largest Rectangle in Histogram #12
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,180 @@ | ||
| ## step1 とりあえず解く | ||
| - 計算量 | ||
| - 時間:O(N^2) | ||
| - 空間:O(N) | ||
| - Acceptされなかったコード | ||
| - 考えたこととしては、どこまでそのバーの高さを維持できるか調べる | ||
| - 高さが下がればStackから取り出して適宜最大面積を計算していく | ||
| - 最後にStackに残った要素を計算する | ||
| - このコードしか思いつかなかったが、ACできなかった理由としては | ||
| - addFirstしているため単調増加Stackを保てなかった | ||
| - 落ちるケース[3,6,5,7,4,8,1,0] | ||
| - 単調増加できないとpeekLastメソッドの判定がうまくいかない | ||
|
|
||
| ```java | ||
| class Solution { | ||
| private final record ContinuousBar(int index, int height) {}; | ||
| public int largestRectangleArea(int[] heights) { | ||
| ArrayDeque<ContinuousBar> continuousBars = new ArrayDeque<>(); | ||
| int maxSize = 0; | ||
| int heightsLength = heights.length; | ||
|
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. 私はこれ変数に置かないかもしれません。(特に扱いやすくなっていないので。)まあ、置いてもいいでしょう。 |
||
| for (int i = 0; i < heightsLength; i++) { | ||
| while (!continuousBars.isEmpty() && continuousBars.peekLast().height() > heights[i]) { | ||
| ContinuousBar bar = continuousBars.pollLast(); | ||
| maxSize = Math.max(maxSize, (i - bar.index()) * bar.height()); | ||
| continuousBars.addFirst(new ContinuousBar(bar.index(), heights[i])); | ||
| System.out.println("maxSize : " + maxSize + " " + bar.index() + " " + bar.height()); | ||
| } | ||
| continuousBars.add(new ContinuousBar(i, heights[i])); | ||
| } | ||
| while (!continuousBars.isEmpty()) { | ||
| ContinuousBar bar = continuousBars.pollLast(); | ||
| maxSize = Math.max(maxSize, (heightsLength - bar.index()) * bar.height()); | ||
| System.out.println("maxSize2 : " + maxSize + " " + bar.index() + " : " + bar.height()); | ||
| } | ||
| return maxSize; | ||
| } | ||
| } | ||
|
|
||
| ``` | ||
|
|
||
| ## step2 他の人の回答を見る | ||
| - 計算量 | ||
| - 時間:O(N) | ||
| - 空間:O(N) | ||
| - step1で自分が間違えたコードの修正版のようなコード | ||
| - 単調増加Stackを作ることで時間計算量が抑えられる | ||
| - 各要素はadd, pollが一度しかされずO(N) | ||
|
|
||
| ```java | ||
| class Solution { | ||
|
|
||
| private final record RectangleCandidate(int index, int height) {}; | ||
|
|
||
| public int largestRectangleArea(int[] heights) { | ||
| ArrayDeque<RectangleCandidate> rectangleCandidate = new ArrayDeque<>(); | ||
| int maxArea = 0; | ||
|
|
||
| for (int i = 0; i < heights.length; i++) { | ||
| int start = i; | ||
| while (!rectangleCandidate.isEmpty() && rectangleCandidate.peekLast().height() > heights[i]) { | ||
| RectangleCandidate candidate = rectangleCandidate.pollLast(); | ||
| maxArea = Math.max(maxArea, candidate.height() * (i - candidate.index())); | ||
| start = candidate.index(); | ||
| } | ||
| rectangleCandidate.addLast(new RectangleCandidate(start, heights[i])); | ||
| } | ||
|
|
||
|
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. heights の後ろに0を追加すると、後ろのコード不要になりそうですね。(番兵。)
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. 確認ありがとうございます! |
||
| while (!rectangleCandidate.isEmpty()) { | ||
| RectangleCandidate candidate = rectangleCandidate.pollLast(); | ||
| maxArea = Math.max(maxArea, candidate.height() * (heights.length - candidate.index())); | ||
| } | ||
|
|
||
| return maxArea; | ||
| } | ||
| } | ||
|
|
||
| ``` | ||
|
|
||
| - 全探索 | ||
| - 計算量 | ||
| - 時間:O(N^2) | ||
| - 空間:O(1) | ||
| - i番目のバーから見て右、左にどれだけ伸ばせるかを考えるコード | ||
| - 時間計算量が大きいので今回の最適解ではないと感じた | ||
|
|
||
| ```java | ||
| public class Solution { | ||
| public int largestRectangleArea(int[] heights) { | ||
| int n = heights.length; | ||
| int maxArea = 0; | ||
|
|
||
| for (int i = 0; i < n; i++) { | ||
| int height = heights[i]; | ||
|
|
||
| int rightMost = i + 1; | ||
| while (rightMost < n && heights[rightMost] >= height) { | ||
| rightMost++; | ||
| } | ||
|
|
||
| int leftMost = i; | ||
| while (leftMost >= 0 && heights[leftMost] >= height) { | ||
| leftMost--; | ||
| } | ||
|
|
||
| rightMost--; | ||
| leftMost++; | ||
| maxArea = Math.max(maxArea, height * (rightMost - leftMost + 1)); | ||
| } | ||
| return maxArea; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## step3 3回とく | ||
| - Step2で見たStackを使うやり方 | ||
|
|
||
| ```java | ||
| class Solution { | ||
|
|
||
| private final record RectangleCandidate(int index, int height) {}; | ||
|
|
||
| public int largestRectangleArea(int[] heights) { | ||
| ArrayDeque<RectangleCandidate> rectangleCandidate = new ArrayDeque<>(); | ||
| int maxArea = 0; | ||
| for (int i = 0; i < heights.length; i++) { | ||
| int startIndex = i; | ||
| while (!rectangleCandidate.isEmpty() && rectangleCandidate.peekLast().height() > heights[i]) { | ||
| RectangleCandidate candidate = rectangleCandidate.pollLast(); | ||
| maxArea = Math.max(maxArea, candidate.height() * (i - candidate.index())); | ||
| startIndex = candidate.index(); | ||
| } | ||
| rectangleCandidate.add(new RectangleCandidate(startIndex, heights[i])); | ||
| } | ||
| while (!rectangleCandidate.isEmpty()) { | ||
| RectangleCandidate candidate = rectangleCandidate.pollLast(); | ||
| maxArea = Math.max(maxArea, candidate.height() * (heights.length - candidate.index())); | ||
| } | ||
|
|
||
| return maxArea; | ||
| } | ||
| } | ||
|
|
||
| ``` | ||
|
|
||
|
|
||
| ## step4 いただいた指摘を元に修正 | ||
| >heights の後ろに0を追加すると、後ろのコード不要になりそうですね。(番兵。) | ||
|
|
||
| - 上記コメントを元に修正 | ||
| - `System.arraycopy` を用いて配列コピーして最後に0を追加してもよかったが、配列コピーのためにメモリがO(N)追加で必要になるため採用しなかった | ||
|
|
||
| ```java | ||
| class Solution { | ||
|
|
||
| private final record RectangleCandidate(int index, int height) {}; | ||
|
|
||
| public int largestRectangleArea(int[] heights) { | ||
| ArrayDeque<RectangleCandidate> rectangleCandidate = new ArrayDeque<>(); | ||
| int maxArea = 0; | ||
| for (int i = 0; i <= heights.length; i++) { | ||
| int startIndex = i; | ||
| int currentHeight; | ||
| if (i == heights.length) { | ||
| currentHeight = 0; | ||
| } else { | ||
| currentHeight = heights[i]; | ||
| } | ||
| while (!rectangleCandidate.isEmpty() && rectangleCandidate.peekLast().height() > currentHeight) { | ||
| RectangleCandidate candidate = rectangleCandidate.pollLast(); | ||
| maxArea = Math.max(maxArea, candidate.height() * (i - candidate.index())); | ||
| startIndex = candidate.index(); | ||
| } | ||
| rectangleCandidate.add(new RectangleCandidate(startIndex, currentHeight)); | ||
| } | ||
|
|
||
| return maxArea; | ||
| } | ||
| } | ||
|
|
||
| ``` | ||
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.
できればこういうときは最小のケースを書いておきたいです。
[1, 3, 2, 2] であってますか?
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.
最小ケースは両端が低くて中盤に山がくる
[1, 3, 2, 1]です。