695.max area of island#18
Conversation
Added detailed explanation and implementation for the max area of island problem using DFS and Union-Find methods.
| ``` | ||
|
|
||
| ユニオンファインドは | ||
| 1.親をそれぞれの配列の要素が持ち、その親の親の親……と累進した最後の場所の親であるrootをある島の代表として扱う。 |
There was a problem hiding this comment.
「累進」という表現に違和感ありますが、あえてこの単語を使った意図はありますか?
There was a problem hiding this comment.
レビューありがとうございます。
こういう表現を見たことがあったので特に意図があってのことではないのですが、遡ると書いた方がいいですね。
| }; | ||
| ``` | ||
|
|
||
| ユニオンファインドは |
There was a problem hiding this comment.
Union-Findというデータ構造自体の説明とこの問題固有の話を混同しているようです。別々に記述できますか?
There was a problem hiding this comment.
難しいです。ユニオンファインドに触れたのは今回が初めてなので、これが典型的に用いられる場面が分かっていません。
parent,root,unite,find辺りがデータ構造の話で、縦横に動くというのが固有の話でしょうか。
There was a problem hiding this comment.
AIに聞いたり、Googleで検索したりしましたか?この話に限らずですが…
There was a problem hiding this comment.
まずは、Union-Findとはどのようなデータ構造であるか、からですかね。
There was a problem hiding this comment.
@liquo-rice @h-masder
ご返信ありがとうございます。お時間を使ってくださっているのに「分からない」で済ませて申し訳ありません。
一応geminiとgoogleは使っています。
union-findはunion(x,y)とfind(x)をメンバー関数として持つアルゴリズムで、木やリストによって実装されます。今回はリストで実装しています。それぞれの要素の所属する集合は素集合(和集合=空集合)であるように配置されます。union(x,y)によりxとyの属する集合を結合します。find(x)によりxの属する集合を判明させます。結合の方法には効率的な方法があります。ある規則で複数の要素を数えるときなどに有効性があります。
There was a problem hiding this comment.
その説明なのですが、素集合系に属する要素(集合)同士の和集合が空集合というのは誤りですね。和集合は、積集合の間違いかと思われます。全体的に言葉の意味を理解して使っているように見えないと読み取れる文章が多々あるように見受けられます。
腑に落ちない場合はとりあえず先に進んでも大丈夫だとは思いますが、分からないことと分かることを区別できるのは大事だと思います。
例えば、メモに「Union-Findの実装は理解したが、用途や数学的な意味はまだピンと来ていない」などと書いておいて、後で振り返って考えてみると良いかもしれません。
There was a problem hiding this comment.
@liquo-rice
ありがとうございます。積集合でした。
そうですね、プログラムの手順と理解度を分けて書いておこうと思います。
| int count = 0; | ||
| if (0 <= i && i < grid.size() && 0 <= j && j < grid[0].size() && | ||
| grid[i][j] == 1 && !visited[i][j]) { | ||
| visited[i][j] = true; | ||
| count = 1 + count_island(visited, grid, i - 1, j) + | ||
| count_island(visited, grid, i + 1, j) + | ||
| count_island(visited, grid, i, j - 1) + | ||
| count_island(visited, grid, i, j + 1); | ||
| } | ||
| return count; |
There was a problem hiding this comment.
int island(vector<vector<int>>& grid, vector<vector<bool>>& visited, int i,
int j) {
int count = 0;
if (0 > i || i >= grid.size() || 0 > j || j >= grid[0].size())
return 0;
if (grid[i][j] == 0 || visited[i][j])
return 0;
visited[i][j] = true;
return island(grid, visited, i - 1, j) +
island(grid, visited, i + 1, j) +
island(grid, visited, i, j - 1) +
island(grid, visited, i, j + 1) + 1;
}こうなりますね。
There was a problem hiding this comment.
if (0 > i || i >= grid.size() || 0 > j || j >= grid[0].size())
この部分が読みにくく感じました。元のコード同様、数直線上に一直線に並ぶよう並べたほうが読みやすいと思います。
if (!(0 <= i && i < grid.size() && 0 <= j && j < grid[0].size())) {| for (int i = 0; i < grid.size(); i++) { | ||
| for (int j = 0; j < grid[0].size(); j++) { | ||
| if (grid[i][j] == 1 && !visited[i][j]) { | ||
| int temp = count_island(visited, grid, i, j); |
There was a problem hiding this comment.
うーん、思いつきません。
temp_countはどうでしょうか。ご意見をお聞かせください。
There was a problem hiding this comment.
ありがとうございます。各島の面積<=最大の島の面積なので意味とやっていることが一致しますね。
| int m = grid.size(); | ||
| int n = grid[0].size(); |
| for (int i = 0; i < maxsize; i++) { | ||
| parent[i] = i; | ||
| } |
There was a problem hiding this comment.
iota(parent.begin(), parent.end(), 0)と書けますね。
There was a problem hiding this comment.
ありがとうございます。iotaという便利な関数があるのですね。
|
|
||
| 200.number of islandsで使用したのと同様のDFSの手段を使用したがデータの破壊を避けるために島を沈没させずにvisitedにて訪問を記録した。 | ||
| 1.まずcount_island関数を作る。これは配列の(i,j)地点を与えられると、それが島なら一続きの島の面積を返し、海なら0を返す。 | ||
| 2.これの中身は再帰関数になっており、訪問記録visitedと配列gridを(i,j)と共に引数にする。もし(i,j)地点が島なら、(i,j)をvisitedに追加し、(i,j)の四方一マスについて自分自身を呼び出して探索する。 |
There was a problem hiding this comment.
(i,j)をvisitedに追加し
とありますが、visitedはvector<bool>ではないですか?
There was a problem hiding this comment.
そうですね、(i,j)を訪れたのを記録するという意味で書きましたが不正確でした。
visited[i][j]をtrueにする、と書いたほうが良かったです。
| 200.number of islandsで使用したのと同様のDFSの手段を使用したがデータの破壊を避けるために島を沈没させずにvisitedにて訪問を記録した。 | ||
| 1.まずcount_island関数を作る。これは配列の(i,j)地点を与えられると、それが島なら一続きの島の面積を返し、海なら0を返す。 | ||
| 2.これの中身は再帰関数になっており、訪問記録visitedと配列gridを(i,j)と共に引数にする。もし(i,j)地点が島なら、(i,j)をvisitedに追加し、(i,j)の四方一マスについて自分自身を呼び出して探索する。 | ||
| 3.再帰の一回ごとに現在地点が島ならカウンターに+1をする。島の面積がわかるのであとはgridを走査する。 |
There was a problem hiding this comment.
島の面積がわかるのであとはgridを走査する
論理関係がおかしい記述になっていそうでしょうか?
There was a problem hiding this comment.
はい、なっています。
そうすることである島の面積がわかるので、gridを走査すると最大の面積の島がわかる
と書いた方がよいです。
There was a problem hiding this comment.
読んでアルゴリズムがイメージできる説明ではなさそうに見えました。
「gridを走査し、未探索の島ならcount_island()で面積を求め、最大値を探す。」とかでどうでしょう?
There was a problem hiding this comment.
そうですね、プログラムの動作としてはこの記述が正しいです。元の記述は思いつくまでの過程、思考を書きすぎています。
| @@ -0,0 +1,124 @@ | |||
| 問題:https://leetcode.com/problems/max-area-of-island/description/ | |||
| int count = 0; | ||
| if (0 <= i && i < grid.size() && 0 <= j && j < grid[0].size() && | ||
| grid[i][j] == 1 && !visited[i][j]) { | ||
| visited[i][j] = true; | ||
| count = 1 + count_island(visited, grid, i - 1, j) + | ||
| count_island(visited, grid, i + 1, j) + | ||
| count_island(visited, grid, i, j - 1) + | ||
| count_island(visited, grid, i, j + 1); | ||
| } | ||
| return count; |
There was a problem hiding this comment.
if (0 > i || i >= grid.size() || 0 > j || j >= grid[0].size())
この部分が読みにくく感じました。元のコード同様、数直線上に一直線に並ぶよう並べたほうが読みやすいと思います。
if (!(0 <= i && i < grid.size() && 0 <= j && j < grid[0].size())) {| ```cpp | ||
| class Solution { | ||
| private: | ||
| int count_island(vector<vector<bool>>& visited, |
There was a problem hiding this comment.
vector<bool> は特殊化されたコンテナであり、通常の vector<T> とは挙動が一部異なります。要素アクセスにはプロキシオブジェクトが用いられるため、場合によっては動作がやや複雑になったり、オーバーヘッドが発生したりする可能性があります。
また、要素のアドレスを取得できないなど、通常の配列的な扱いができない点にも注意が必要です。
このような特殊性から、vector<bool> の使用を避ける方針のチームもあります。特別な理由がない限りは、vector<char> や vector<uint8_t> などを使うほうが無難だと思います。
| class Solution { | ||
| private: | ||
| int count_island(vector<vector<bool>>& visited, | ||
| const vector<vector<int>>& grid, int i, int j) { |
There was a problem hiding this comment.
こちらのコメントをご参照ください。
mamo3gr/arai60#16 (comment)
This problem: https://leetcode.com/problems/max-area-of-island/
Next problem: https://leetcode.com/problems/word-ladder/description/