-
Notifications
You must be signed in to change notification settings - Fork 0
695. Max Area of Island #19
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,28 @@ | ||
| ## 考察 | ||
| - 初見の問題 | ||
| - 問題設定は前回の Number of Islands とほぼ同じ | ||
| - 連結成分のノードの数をカウントすればOK | ||
| - 方針 | ||
| - DFS | ||
| - BFS | ||
| - Union Find | ||
| - 前回と同じ | ||
| - まずは実装しやすいDFSでやる | ||
| - 再帰の深さは最大でも250 -> 大丈夫 | ||
| - 訪問済みの管理はgridと同じ大きさのvisitedを作って管理 | ||
| - あとは実装 | ||
|
|
||
| ## Step1 | ||
| - DFSで実装 | ||
| - time: O(mn), space: O(mn) | ||
|
|
||
| ## Step2 | ||
| - BFSとUnion Findでも実装 | ||
| - `step2_bfs.py` | ||
| - `step2_union_find.py` | ||
| - Union Findには、パス圧縮とUnion by Rankをともに入れた | ||
|
|
||
| ## Step3 | ||
| - 1回目: 4m30s | ||
| - 2回目: 3m35 | ||
| - 3回目: 3m30 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| LAND = 1 | ||
| WATER = 0 | ||
| n_row = len(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. rowの数を表しているかと思いますが、
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. ありがとうございます。 |
||
| n_col = len(grid[0]) | ||
| visited = [[False] * n_col for _ in range(n_row)] | ||
|
|
||
| def calculate_area(row: int, col: int) -> int: | ||
| is_water = ( | ||
|
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. 個人的にこれはrow, colを引数にとった関数として定義するほうが好みです。 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. is_water という名前に対して、領域内かの判定もしていることが気になりました。 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. コメントありがとうございます。 @sakupan102 @goto-untrapped 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. 関数が良いのは再利用ができると思ったからです。 |
||
| not 0 <= row < n_row | ||
| or not 0 <= col < n_col | ||
| or grid[row][col] == WATER | ||
| ) | ||
| if is_water or visited[row][col]: | ||
| return 0 | ||
|
|
||
| visited[row][col] = True | ||
| area = 1 | ||
| drow = (0, 1, 0, -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. こちらもdはdeltaの略かと思いますが、省略せずに
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. こちらも |
||
| dcol = (1, 0, -1, 0) | ||
| for direction in range(4): | ||
|
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. この数字はdirectionを表すものでは無い気がします。iでいいかなと思いました。
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. 0-3は右下左上の4方向と一対一対応していると思いますが、微妙でしょうか、、? 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. 自分のdirectionのイメージは (0, 1) とか (-1, 0) とかで、それらとは違うかなと思ってコメントしました ( |
||
| area += calculate_area(row + drow[direction], col + dcol[direction]) | ||
| return area | ||
|
|
||
| max_area = 0 | ||
| for i in range(n_row): | ||
| for j in range(n_col): | ||
| if grid[i][j] == LAND and not 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. この条件に反しても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. たしかにこの条件がなくても動きますが、それだと実装に依存したロジックになりませんか? 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. 確かに関数の実装の仕方によって結果が変わる可能性はありますね。 |
||
| max_area = max(max_area, calculate_area(i, j)) | ||
| return max_area | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| LAND = 1 | ||
| WATER = 0 | ||
| n_row = len(grid) | ||
| n_col = len(grid[0]) | ||
| visited = [[False] * n_col for _ in range(n_row)] | ||
|
|
||
| def calculate_area(row: int, col: int) -> int: | ||
| area = 0 | ||
| visited[row][col] = True | ||
| node_que = deque([(row, col)]) | ||
|
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. queueのtypoか、省略でしょうか?あまり見ない書き方だとは思います。
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. queはqueueの省略のつもりでした。ここの命名が微妙なので 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. たしかにちょっと抽象的過ぎますね。いい名前が思いつきませんでした。 |
||
| while node_que: | ||
| current_row, current_col = node_que.pop() | ||
| area += 1 | ||
| drow = (0, 1, 0, -1) | ||
| dcol = (1, 0, -1, 0) | ||
| for direction in range(4): | ||
| next_row = current_row + drow[direction] | ||
| next_col = current_col + dcol[direction] | ||
| is_land = ( | ||
| 0 <= next_row < n_row | ||
| and 0 <= next_col < n_col | ||
| and grid[next_row][next_col] == LAND | ||
| ) | ||
| if is_land and not visited[next_row][next_col]: | ||
| visited[next_row][next_col] = True | ||
|
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. どちらが良いとかではないかもですが、自分はqueueに入れるのはこれから行く場所の予約で、popするときにvisitをする感覚なのでpop()の次の行にこの処理を書きますね (一応
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. たしかに...!自分が言ったような実装をする場合はpopした位置が訪問済みならcontinueするみたいな処理を入れないとダメですね。気づかなかったです、ありがとうございます 🙏 |
||
| node_que.append((next_row, next_col)) | ||
| return area | ||
|
|
||
| max_area = 0 | ||
| for i in range(n_row): | ||
| for j in range(n_col): | ||
| if grid[i][j] == LAND and not visited[i][j]: | ||
| max_area = max(max_area, calculate_area(i, j)) | ||
| return max_area | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| class UnionFind: | ||
|
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. このUnionFindのアルゴリズム、自分にはなぜ動くのか分かりませんでした... なにか参考にした資料などあるでしょうか?
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. parent_size -> この変数名良くないですね。見直します。 可読性を考えるとシンプルにself.parentとself.sizeに分けた方が良さそうに思いました。 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.
なるほど、理解できた気がします! self.parent_size[x] += self.parent_size[y]
self.parent_size[y] = x↑で上の行は常に負同士の足し算だから、マージ後の新しい根の側には負の値が入り、下の行で根じゃなくなった方には根の番号が入りますね。ありがとうございます 🙏
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. はい、まさにその通りです。こちらこそコメントいただきありがとうございました! |
||
| def __init__(self, n): | ||
| self.parent_size = [-1] * n | ||
|
|
||
| def find(self, a): | ||
| if self.parent_size[a] < 0: | ||
| return a | ||
| self.parent_size[a] = self.find(self.parent_size[a]) | ||
| return self.parent_size[a] | ||
|
|
||
| def unite(self, a, b): | ||
| x = self.find(a) | ||
| y = self.find(b) | ||
| if x == y: | ||
| return | ||
| if abs(self.parent_size[x]) < abs(self.parent_size[y]): | ||
| x, y = y, x | ||
| self.parent_size[x] += self.parent_size[y] | ||
| self.parent_size[y] = x | ||
|
|
||
| def size(self, a): | ||
| return abs(self.parent_size[self.find(a)]) | ||
|
|
||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| LAND = 1 | ||
| WATER = 0 | ||
| n_row, n_col = len(grid), len(grid[0]) | ||
| uf = UnionFind(n_row * n_col) | ||
|
|
||
| def index(row, col): | ||
| return row * n_col + col | ||
|
|
||
| for row in range(n_row): | ||
| for col in range(n_col): | ||
| if grid[row][col] == WATER: continue | ||
| drow = (0, 1, 0, -1) | ||
| dcol = (1, 0, -1, 0) | ||
|
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. drow = (0, 1)
dcol = (1, 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. どのように使用するイメージでしょうか。右下左上の4方向に一対一対応させたい意図があります。
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. あ、ここ理解しました! |
||
| for direction in range(4): | ||
| next_row = row + drow[direction] | ||
| next_col = col + dcol[direction] | ||
| is_land = ( | ||
| 0 <= next_row < n_row | ||
| and 0 <= next_col < n_col | ||
| and grid[next_row][next_col] == LAND | ||
| ) | ||
| if is_land: | ||
| uf.unite(index(row, col), index(next_row, next_col)) | ||
|
|
||
| max_area = 0 | ||
| for row in range(n_row): | ||
| for col in range(n_col): | ||
| if grid[row][col] == LAND: | ||
| max_area = max(max_area, uf.size(index(row, col))) | ||
| return max_area | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| LAND = 1 | ||
| WATER = 0 | ||
| n_row = len(grid) | ||
| n_col = len(grid[0]) | ||
| visited = [[False] * n_col for _ in range(n_row)] | ||
|
|
||
| def calculate_area(row: int, col: int) -> int: | ||
| is_water = ( | ||
|
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 範囲外:
return 0
if 水:
return 0
if visited[][]:
return 0と分けるかも知れません。 |
||
| not 0 <= row < n_row | ||
| or not 0 <= col < n_col | ||
| or grid[row][col] == WATER | ||
| ) | ||
| if is_water or visited[row][col]: | ||
| return 0 | ||
|
|
||
| visited[row][col] = True | ||
| area = 1 | ||
| drow = (0, 1, 0, -1) | ||
| dcol = (1, 0, -1, 0) | ||
|
Comment on lines
+20
to
+21
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. ペアとして定義するのも良さそうです。ありがとうございます。 |
||
| for direction in range(4): | ||
|
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. drow や dcol を使うとか、定数で定義した方がいいのかなと思いました。
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. おっしゃる通りです。マジックナンバーは避けた方がいいですね。 |
||
| area += calculate_area(row + drow[direction], col + dcol[direction]) | ||
| return area | ||
|
|
||
| max_area = 0 | ||
| for i in range(n_row): | ||
| for j in range(n_col): | ||
| if grid[i][j] == WATER or visited[i][j]: continue | ||
| max_area = max(max_area, calculate_area(i, j)) | ||
| return max_area | ||
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.
m == grid.length
n == grid[i].length
1 <= m, n <= 50
なので最大50*50=2500じゃないでしょうか?
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.
2500ですね。ご指摘ありがとうございます。