-
Notifications
You must be signed in to change notification settings - Fork 0
695. Max Area of Island #2
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,153 @@ | ||
|
|
||
| ## step1: | ||
| まずどこかlandに着いたら深さ優先探索でその島を探索し尽くそうと思い、dfs関数で上下左右で未探索かつlandである場所を探索していった。ここで、どうやって各島の面積を保存しようと思い悩み、関数に数値を保存するオブジェクトを渡してlandを見つけるたびに1づつ足していけばいいと考えた。そこで各島にラベルを付け、島を見つけるたびに各ラベルに1づつ足していき最後にそれらのmax値を返却した。 | ||
|
|
||
| ### code | ||
| ```python | ||
| from collections import defaultdict | ||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| m, n = len(grid), len(grid[0]) | ||
| visited = [[0]*n for _ in range(m)] | ||
| max_area = 0 | ||
| area_dict = defaultdict(int) | ||
| label_max = 0 | ||
|
|
||
| def dfs(p, q, dict, label): | ||
|
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. 関数名は動詞の原型または命令形から始まることが多いように思います。また、 dfs という単語は、関数の実装内容の詳細に示し過ぎているように思います。 traverse はいかがでしょうか?
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. claudeに聞いてみると
と来たので今回は副作用をもたらす関数として使ってるのでtraverseが良さそうですね。 |
||
| nonlocal visited | ||
| visited[p][q] = 1 | ||
| area_dict[label] += 1 | ||
| if p-1 >= 0 and visited[p-1][q] == 0 and grid[p-1][q] == 1: | ||
| dfs(p-1, q, area_dict, label) | ||
| if p+1 < m and visited[p+1][q] == 0 and grid[p+1][q] == 1: | ||
| dfs(p+1, q, area_dict, label) | ||
| if q-1 >= 0 and visited[p][q-1] == 0 and grid[p][q-1] == 1: | ||
| dfs(p, q-1, area_dict, label) | ||
| if q+1 < n and visited[p][q+1] == 0 and grid[p][q+1] == 1: | ||
| dfs(p, q+1, area_dict, label) | ||
|
|
||
| for i in range(m): | ||
| for j in range(n): | ||
| if visited[i][j] == 0 and grid[i][j] == 1: | ||
| dfs(i, j, area_dict, label_max) | ||
| label_max += 1 | ||
| visited[i][j] = 1 | ||
| if len(area_dict.values()) == 0: | ||
|
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.
|
||
| return 0 | ||
| max_area = max(area_dict.values()) | ||
| return max_area | ||
| ``` | ||
|
|
||
| ## step2: | ||
| 最後のmax_areaを求めるところを、各島の面積を求めたところで判別できると感じたので削除した。 | ||
|
|
||
| ### code | ||
| ```python | ||
| from collections import defaultdict | ||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| m, n = len(grid), len(grid[0]) | ||
| visited = [[0]*n for _ in range(m)] | ||
| max_area = 0 | ||
| area_dict = defaultdict(int) | ||
| label_max = 0 | ||
|
|
||
| def dfs(p, q, dict, label): | ||
| nonlocal 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. Step 3では消えていますが、不要ですね。 |
||
| visited[p][q] = 1 | ||
| area_dict[label] += 1 | ||
| if p-1 >= 0 and visited[p-1][q] == 0 and grid[p-1][q] == 1: | ||
| dfs(p-1, q, area_dict, label) | ||
| if p+1 < m and visited[p+1][q] == 0 and grid[p+1][q] == 1: | ||
| dfs(p+1, q, area_dict, label) | ||
| if q-1 >= 0 and visited[p][q-1] == 0 and grid[p][q-1] == 1: | ||
| dfs(p, q-1, area_dict, label) | ||
| if q+1 < n and visited[p][q+1] == 0 and grid[p][q+1] == 1: | ||
| dfs(p, q+1, area_dict, label) | ||
|
|
||
| for i in range(m): | ||
| for j in range(n): | ||
| if visited[i][j] == 0 and grid[i][j] == 1: | ||
| dfs(i, j, area_dict, label_max) | ||
| max_area = max(max_area, area_dict[label_max]) | ||
| label_max += 1 | ||
| visited[i][j] = 1 | ||
| return max_area | ||
| ``` | ||
|
|
||
|
|
||
| ## step3: | ||
|
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を使わない、iterative DFS/BFS、union findなど色々あるかと。 |
||
|
|
||
| ### code | ||
| ```python | ||
| from collections import defaultdict | ||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| m, n = len(grid), len(grid[0]) | ||
| visited = [[0]*n for _ in range(m)] | ||
| max_area = 0 | ||
| area_dict = defaultdict(int) | ||
|
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. 確かにlabelをいちいちインクリメントして格納しておく必要はなかったですね... |
||
| max_label = 0 | ||
|
|
||
| def dfs(p, q, dict, label): | ||
|
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. built-in typesをシャドーしない方がいいと思います。 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. p, qをmatrixのインデックスとして使うのは珍しい気がします。i, jやrow, col、y, xが一般的だと思います。 |
||
| visited[p][q] = 1 | ||
| dict[label] += 1 | ||
| if p-1 >= 0 and visited[p-1][q] == 0 and grid[p-1][q] == 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. 下で言及ありますが、やや繰り返しがすぎるように感じました。8方向に繋がっている場合とかだと、どうするかを考えると良いかもしれません。 |
||
| dfs(p-1, q, dict, label) | ||
| if p+1 < m and visited[p+1][q] == 0 and grid[p+1][q] == 1: | ||
| dfs(p+1, q, dict, label) | ||
| if q-1 >= 0 and visited[p][q-1] == 0 and grid[p][q-1] == 1: | ||
| dfs(p, q-1, dict, label) | ||
| if q+1 < n and visited[p][q+1] == 0 and grid[p][q+1] == 1: | ||
| dfs(p, q+1, dict, label) | ||
|
|
||
| for i in range(m): | ||
| for j in range(n): | ||
| if visited[i][j] == 0 and grid[i][j] == 1: | ||
| dfs(i, j, area_dict, max_label) | ||
|
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_dictは引数で渡していますが、visitedはenclosing scopeからアクセスするのは一貫性がないように感じました。 |
||
| max_area = max(max_area, area_dict[max_label]) | ||
| max_label += 1 | ||
| visited[i][j] = 1 | ||
| return max_area | ||
| ``` | ||
|
|
||
| ## 他の方のコードを読んだ所感 | ||
| https://github.com/hemispherium/LeetCode_Arai60/pull/18/changes | ||
| 遷移先でgridの外に出てしまうか判断しているので、自分のコードのように何度もif文を書く必要がなくバグが出にくい。cppはintがimmutableでないのでそのままdfsの関数の引数に入れてインクリメントして大丈夫そうである。自分は今回visitedという配列を用いて訪問済みか判断していたが、この方はgridを0にしていて訪問済みのマークと同等の効果を出していて効果的だと感じた。 | ||
|
|
||
| https://github.com/Manato110/LeetCode-arai60/pull/18/changes | ||
| この方はnum_rows, num_colsと名付けていたが問題文でm×nと定義されているのでm, nで定義した方が簡潔な気がする。あと関数をクラスの中の1つの関数としていたので、関数の中での関数として定義していた自分よりもテストがしやすい。 | ||
| ```python | ||
| if not (0 <= row < num_rows and 0 <= col < num_cols): | ||
| ``` | ||
| この条件式の書き方は参考にできる。0, 1は条件文でWATER, LANDとなっているが、この方はクラス内で改めてWATER = 0, LAND = 1と書いて条件式でself.WATERと書いているので非常に可読性が良い。visited判定もset()に訪れた座標を入れていて、setは確か内部的にハッシュテーブルを利用しているはずなのでO(1)でアクセスできる。よって自分の書いたvisited配列と同じメモリ計算量、時間計算量で利用できる。 | ||
|
|
||
| ## iterative dfsで解いてみた | ||
| ```python | ||
| class Solution: | ||
| def maxAreaOfIsland(self, grid: List[List[int]]) -> int: | ||
| max_area = 0 | ||
| m, n = len(grid), len(grid[0]) | ||
|
|
||
| def get_area_starting_from(i, j): | ||
| stack = [] | ||
| area = 0 | ||
| stack.append((i, j)) | ||
| while stack: | ||
| y, x = stack.pop() | ||
| if not (0 <= y < m and 0 <= x < n and grid[y][x]): | ||
| continue | ||
| grid[y][x] = 0 | ||
| area += 1 | ||
| for col, row in [(y-1, x), (y+1, x), (y, x-1), (y, x+1)]: | ||
| stack.append((col, row)) | ||
| return area | ||
|
|
||
| for i in range(m): | ||
| for j in range(n): | ||
| if grid[i][j] == 1: | ||
| max_area = max(max_area, get_area_starting_from(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.
こちらのコメントをご参照ください。
mt2324/leetcode#2 (comment)