-
Notifications
You must be signed in to change notification settings - Fork 0
695.max area of island #18
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,124 @@ | ||
| 問題:https://leetcode.com/problems/max-area-of-island/description/ | ||
|
|
||
| ## step1 | ||
|
|
||
| 問題は | ||
| 1.vector<vector<int>>のm行n列の配列に1,0が入っている。 | ||
| 2.1を島とし、0を海とする。島は上下左右につながって一つの島として数える。斜めにつながる島は一つの島と数えない。 | ||
| 3.最も大きい島に何個の1が含まれるか、面積を答えよ | ||
| というもの。 | ||
|
|
||
| 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. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
とありますが、visitedは
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. そうですね、(i,j)を訪れたのを記録するという意味で書きましたが不正確でした。 |
||
| 3.再帰の一回ごとに現在地点が島ならカウンターに+1をする。島の面積がわかるのであとはgridを走査する。 | ||
|
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.
論理関係がおかしい記述になっていそうでしょうか?
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. はい、なっています。
と書いた方がよいです。 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. 読んでアルゴリズムがイメージできる説明ではなさそうに見えました。 「gridを走査し、未探索の島ならcount_island()で面積を求め、最大値を探す。」とかでどうでしょう?
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. そうですね、プログラムの動作としてはこの記述が正しいです。元の記述は思いつくまでの過程、思考を書きすぎています。 |
||
|
|
||
| 時間計算量は走査するのでO(MN)で、空間計算量はO(MN)である。スタック領域に再帰が積み重なることで最悪の場合はgridの要素一つ一つに対してメモリを使用する。 | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| private: | ||
| int count_island(vector<vector<bool>>& visited, | ||
|
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. vector<bool> は特殊化されたコンテナであり、通常の vector<T> とは挙動が一部異なります。要素アクセスにはプロキシオブジェクトが用いられるため、場合によっては動作がやや複雑になったり、オーバーヘッドが発生したりする可能性があります。 |
||
| const vector<vector<int>>& grid, int i, int j) { | ||
|
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. こちらのコメントをご参照ください。 |
||
| 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; | ||
|
Comment on lines
+23
to
+32
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. Early returnで書き直すとどうなりますか?
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. 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. 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.
この部分が読みにくく感じました。元のコード同様、数直線上に一直線に並ぶよう並べたほうが読みやすいと思います。 if (!(0 <= i && i < grid.size() && 0 <= j && j < grid[0].size())) { |
||
| } | ||
|
|
||
| public: | ||
| int maxAreaOfIsland(vector<vector<int>>& grid) { | ||
| int m = grid.size(); | ||
| int n = grid[0].size(); | ||
|
Comment on lines
+37
to
+38
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ループで使うのを忘れているようです。 |
||
| vector<vector<bool>> visited(m, vector<bool>(n, false)); | ||
| int count = 0; | ||
| 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. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. より適切な変数名は思いつきますか?
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. うーん、思いつきません。 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.
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. ありがとうございます。各島の面積<=最大の島の面積なので意味とやっていることが一致しますね。 |
||
| count = (count < temp) ? temp : count; | ||
| } | ||
| } | ||
| } | ||
| return count; | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| ## step2 | ||
|
|
||
| 他の方のコードとコメント集みた。 | ||
| 以下の方を参考にユニオンファインドやってみる。 | ||
| 参考:https://github.com/quinn-sasha/leetcode/pull/30/changes | ||
|
|
||
| ```cpp | ||
| class UnionFind { | ||
| vector<int> parent; | ||
| vector<int> size; | ||
|
|
||
| public: | ||
| UnionFind(int maxsize) : parent(maxsize), size(maxsize, 1) { | ||
| for (int i = 0; i < maxsize; i++) { | ||
| parent[i] = i; | ||
| } | ||
|
Comment on lines
+67
to
+69
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.
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. ありがとうございます。iotaという便利な関数があるのですね。 |
||
| } | ||
| int find(int x) { | ||
| if (parent[x] == x) { | ||
| return x; | ||
| } | ||
| return parent[x] = find(parent[x]); | ||
| } | ||
| int unite(int x, int y) { | ||
| int x_root = find(x); | ||
| int y_root = find(y); | ||
| if (x_root == y_root) { | ||
| return x_root; | ||
| } | ||
| if (size[x_root] < size[y_root]) { | ||
| swap(x_root, y_root); | ||
| } | ||
| parent[y_root] = x_root; | ||
| size[x_root] += size[y_root]; | ||
| return x_root; | ||
| } | ||
| int get_size(int x) { return size[find(x)]; } | ||
| }; | ||
| class Solution { | ||
| public: | ||
| int maxAreaOfIsland(vector<vector<int>>& grid) { | ||
| int num_rows = grid.size(); | ||
| int num_cols = grid[0].size(); | ||
| UnionFind uf(num_rows * num_cols); | ||
| int max_area = 0; | ||
| for (int row = 0; row < num_rows; row++) { | ||
| for (int col = 0; col < num_cols; col++) { | ||
| if (grid[row][col] == 0) { | ||
| continue; | ||
| } | ||
| max_area = max(max_area, 1); | ||
| int id = row * num_cols + col; | ||
| if (col + 1 < num_cols && grid[row][col + 1] == 1) { | ||
| int root = uf.unite(id, row * num_cols + col + 1); | ||
| max_area = max(max_area, uf.get_size(root)); | ||
| } | ||
| if (row + 1 < num_rows && grid[row + 1][col] == 1) { | ||
| int root = uf.unite(id, (row + 1) * num_cols + col); | ||
| max_area = max(max_area, uf.get_size(root)); | ||
| } | ||
| } | ||
| } | ||
| return max_area; | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| ユニオンファインドは | ||
|
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. Union-Findというデータ構造自体の説明とこの問題固有の話を混同しているようです。別々に記述できますか?
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. 難しいです。ユニオンファインドに触れたのは今回が初めてなので、これが典型的に用いられる場面が分かっていません。 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. AIに聞いたり、Googleで検索したりしましたか?この話に限らずですが… 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. まずは、Union-Findとはどのようなデータ構造であるか、からですかね。
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. @liquo-rice @h-masder union-findはunion(x,y)とfind(x)をメンバー関数として持つアルゴリズムで、木やリストによって実装されます。今回はリストで実装しています。それぞれの要素の所属する集合は素集合(和集合=空集合)であるように配置されます。union(x,y)によりxとyの属する集合を結合します。find(x)によりxの属する集合を判明させます。結合の方法には効率的な方法があります。ある規則で複数の要素を数えるときなどに有効性があります。 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. その説明なのですが、素集合系に属する要素(集合)同士の和集合が空集合というのは誤りですね。和集合は、積集合の間違いかと思われます。全体的に言葉の意味を理解して使っているように見えないと読み取れる文章が多々あるように見受けられます。 腑に落ちない場合はとりあえず先に進んでも大丈夫だとは思いますが、分からないことと分かることを区別できるのは大事だと思います。 例えば、メモに「Union-Findの実装は理解したが、用途や数学的な意味はまだピンと来ていない」などと書いておいて、後で振り返って考えてみると良いかもしれません。
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. @liquo-rice |
||
| 1.親をそれぞれの配列の要素が持ち、その親の親の親……と累進した最後の場所の親であるrootをある島の代表として扱う。 | ||
|
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. 「累進」という表現に違和感ありますが、あえてこの単語を使った意図はありますか?
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. レビューありがとうございます。 |
||
| 2.これがどのように決められるかというと横の走査と縦の走査を行うことによる。隣の一つも島である場合、自分と隣のrootを比較してより多くの子供がいる方にuniteしてrootを一種類にする。 | ||
| 3.島のサイズはrootに紐づいて管理される。 | ||
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.
ちなみにStep 3で3回書き直すのはやっていますか?
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.
はい、やっています。今回は再帰でやりました。