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
165 changes: 160 additions & 5 deletions graph-bfs-dns/695.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,161 @@
- 問題: []()
- コメント集: [](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/mobilebasic#h.o0jquy48e6cy)
- 問題: [695. Max Area of Island](https://leetcode.com/problems/max-area-of-island/description/)
- コメント集: [695. Max Area of Island](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/mobilebasic#h.o0jquy48e6cy)
- 先にQueueに詰めてしまう方針はなるほどと思った
- Taple, Java でいう Record を使う方法が出てきたが今回のような短い処理であれば不要だと考える。もう少し長い処理なら変数を明示的にかけるので良い気がする。
- 条件
- 方針1
- 時間計算量:
- 空間計算量:
- `m == grid.length`
- `n == grid[i].length`
- `1 <= m, n <= 50`
- `grid[i][j] is either 0 or 1.`
- 方針
- DFS
- number of island の方針と大体同じ
- 二重ループで grid を走査、この時点で`1` or `0` 以外を含んでいた場合、`IllegalArgumentException()`を投げる
- また、引数 grid を変更するのは呼び出し者の意図に反するため、状態管理用のboolリストを用意して状態管理を切り出す
- `grid[row][index] == land`なら、その地点から上下左右を深さ優先で探索する
- 探索開始地点カウントを1として、上下左右で見つけた島の数をコールスタックが戻ってきた時に足し合わせて最後に返却する
- 時間計算量: O(m*n)
- 空間計算量: O(m*n)
- スタックメモリを使うのでスタックオーバーフローに注意する
- BFS
- DFSと同じ、探索の方法でQueueを使うだけ
- 時間計算量: O(m*n)
- 空間計算量: O(m*n)
- ヒープメモリを使う
- 感想
- 今回の問題は個人的にはDFSの方が書きやすい
- が、過去にリプレイス案件で既存実装を読んだコードで、「なんでこの処理を再帰関数で書いてんの?!?!ああ、、これ自分にしか読めないコードをわざわざ書いて自分にしかわからない領域を作ろうとしたっぽく見えるぞ、、SEWの風上にもおけん」と思ったこともあり、、、
- 何でもかんでも再帰関数で書くとコードリーディングは大変になると思っていて、以下のような場合でしか使わないようにしたい
- 今回のようなDFSの意図が分かりやすい問題
- 全経路探索
- 反対にBFSは最短経路を見つけることに特化しているので、DFS,BFSのメリデメと使いどきを常に考えていたい

## DFS

```java
class Solution {
public int maxAreaOfIsland(int[][] grid) {
boolean[][] visited = new boolean[grid.length][grid[0].length];
int maxAreaOfIslands = 0;

for (int rowIndex = 0; rowIndex < grid.length; rowIndex++) {
for (int columnIndex = 0; columnIndex < grid[0].length; columnIndex++) {
int element = grid[rowIndex][columnIndex];

// if element is not land or water.
if (element != 1 && element != 0) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

0, 1は water, land のような定数にした方が扱いやすいと思いました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

そうすれば if (element == land) のように書くことができ、可読性があがるので // if element is land. のようなコメントを削れると思います

throw new IllegalArgumentException("grid array must contains 0 or 1");
}

// if element is land.
if (element == 1) {
maxAreaOfIslands = Math.max(
maxAreaOfIslands,
countNumberOfIslands(grid, visited, rowIndex, columnIndex)
);
}
}
}

return maxAreaOfIslands;
}

private int countNumberOfIslands(int[][] grid, boolean[][] visited, int rowIndex, int columnIndex) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

この関数名だと grid 内の島の数を数えているように見えました。 countAreaOfIsland などいかがでしょう?

// index out of range
if (rowIndex < 0 || columnIndex < 0 || rowIndex >= grid.length || columnIndex >= grid[0].length) {
return 0;
}

// find water
if (grid[rowIndex][columnIndex] == 0 || visited[rowIndex][columnIndex]) {
return 0;
}

visited[rowIndex][columnIndex] = true;
int areaOfIslands = 1;
// count top
areaOfIslands += countNumberOfIslands(grid, visited, rowIndex - 1, columnIndex);
// count bottom
areaOfIslands += countNumberOfIslands(grid, visited, rowIndex + 1, columnIndex);
// count left
areaOfIslands += countNumberOfIslands(grid, visited, rowIndex, columnIndex - 1);
// count right
areaOfIslands += countNumberOfIslands(grid, visited, rowIndex, columnIndex + 1);

return areaOfIslands;
}
}
```
## BFS
```java
class Solution {
public int maxAreaOfIsland(int[][] grid) {
boolean[][] visited = new boolean[grid.length][grid[0].length];
int maxAreaOfIsland = 0;

for (int rowIndex = 0; rowIndex < grid.length; rowIndex++) {
for (int columnIndex = 0; columnIndex < grid[0].length; columnIndex++) {
int element = grid[rowIndex][columnIndex];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

element という変数名には情報が乏しいと思いました(あらゆる配列の要素に関して使えてしまう)。grid の中のセルという意味で cell はどうでしょう?


if (element != 0 && element != 1) {
throw new IllegalArgumentException("grid array must contains 0 or 1");
}

// find land
if (element == 1 && !visited[rowIndex][columnIndex]) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Step1 みたいに、探索の処理は関数に切り出した方が読みやすいと思いました

Queue<int[]> lands = new ArrayDeque<>();
int areaOfIslands = 0;
lands.add(new int[]{rowIndex, columnIndex});
visited[rowIndex][columnIndex] = true;
while (!lands.isEmpty()) {
areaOfIslands++;
int[] index = lands.poll();
int currentRowIndex = index[0];
int currentColumnIndex = index[1];

int nextRowIndex = currentRowIndex + 1;
int previousRowIndex = currentRowIndex - 1;
int nextColumnIndex = currentColumnIndex + 1;
int previousColumnIndex = currentColumnIndex - 1;

// count top
if (previousRowIndex >= 0
&& grid[previousRowIndex][currentColumnIndex] == 1
&& !visited[previousRowIndex][currentColumnIndex]
) {
visited[previousRowIndex][currentColumnIndex] = true;
lands.add(new int[]{previousRowIndex,currentColumnIndex});
}
Comment on lines +121 to +128
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

この処理は4回くり返し書くにはちょっと長く感じました。メソッドに切り出す、長さ4の配列を作りループする、など対処法がコメント集にあったと思うので、見ていなければ見てみると参考になるかもしれません。

// count bottom
if (nextRowIndex < grid.length
&& grid[nextRowIndex][currentColumnIndex] == 1
&& !visited[nextRowIndex][currentColumnIndex]
) {
visited[nextRowIndex][currentColumnIndex] = true;
lands.add(new int[]{nextRowIndex, currentColumnIndex});
}
// count left
if (previousColumnIndex >= 0
&& grid[currentRowIndex][previousColumnIndex] == 1
&& !visited[currentRowIndex][previousColumnIndex]
) {
visited[currentRowIndex][previousColumnIndex] = true;
lands.add(new int[]{currentRowIndex, previousColumnIndex});
}
// count right
if (nextColumnIndex < grid[0].length
&& grid[currentRowIndex][nextColumnIndex] == 1
&& !visited[currentRowIndex][nextColumnIndex]) {
visited[currentRowIndex][nextColumnIndex] = true;
lands.add(new int[]{currentRowIndex, nextColumnIndex});
}
}
maxAreaOfIsland = Math.max(maxAreaOfIsland, areaOfIslands);
}
}
}

return maxAreaOfIsland;
}
}
```