-
Notifications
You must be signed in to change notification settings - Fork 0
200 number of islands medium #28
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?
Conversation
| ranks[root1] += 1 | ||
|
|
||
|
|
||
| directions = ((1, 0), (-1, 0), (0, 1), (0, -1)) |
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.
右と下だけ調べれば十分だと思いました。
directions = ((1, 0), (0, 1))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.
レビューありがとうございます。確かにその通りですね。
| if (neighbor_row, neighbor_column) in seen_lands: | ||
| continue | ||
| traverse_connected_lands(neighbor_row, neighbor_column) | ||
| return |
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.
この return は文法上意味がないため、削除してよいと思います。
| for dr, dc in directions: | ||
| neighbor_row = row + dr | ||
| neighbor_col = col + dc | ||
| if neighbor_row < 0 or neighbor_row >= num_rows: |
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.
数直線上に一直線に並べたほうが読み手にとって読みやすくなると思います。
if not (0 <= neighbor_row and neighbor_row < num_rows):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.
確かにわかりやすいと思いました! 取り入れさせていただきます 🙇
| return num_islands | ||
| ``` | ||
|
|
||
| DFSは、スタックの分だけの空間を使う上、Pythonでは再起呼び出し回数の制限がデフォルトでは1000と小さいので、パフォーマンス上はBFSを用いる方が望ましい。が、DFSの方がコードがシンプルになる場合が多い。 |
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.
DFSをiterativeに(つまり再帰関数を使わずwhileやforなどを使って)書くこともでき、そうすれば再帰関数に関わるデメリットは無くなります。
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.
レビューありがとうございます。
確かにそうですね、再帰関数によるDFS実装、と書くべきですね。
| return num_islands | ||
| ``` | ||
|
|
||
| - gridをinplaceに書き換えてOKならば、`seen_lands.add((row, column))` を`grid[row][column] = "0"` に変更することで、`seen_lands`の代わりに元のグリッドを利用でき、空間計算量を`O(1)`に削減できる。 |
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.
しかし、副作用が生じるのと呼び出した人はびっくりすると思うので、通常は関数入力に対してinplaceに操作する必要はないと思います。
| frontiers.appendleft((initial_row, initial_column)) | ||
| visited_lands.add((initial_row, initial_column)) | ||
| while frontiers: | ||
| row, column = frontiers.pop() |
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.
ここを.popleft()にすればDFS (iterative)になります。
| for column in range(num_columns): | ||
| if not is_land(row, column): | ||
| continue | ||
| if (row, column) in visited_lands: |
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.
()いらないですね。
| visited_lands.add((initial_row, initial_column)) | ||
| while frontiers: | ||
| row, column = frontiers.pop() | ||
| for dr, dc in directions: |
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.
dr, dcは少し認知負荷があると思います。
diff_row, diff_columnくらいが良いと思います。
しかし、今回は範囲がとても狭いのでこれくらい短くても許容かもしれません。
| if not (0 <= neighbor_row < num_rows): | ||
| continue | ||
| if not (0 <= neighbor_col < num_cols): | ||
| continue | ||
| if grid[neighbor_row][neighbor_col] == WATER: | ||
| continue |
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.
問題文に、
You may assume all four edges of the grid are all surrounded by water.
とあり、neighbor_row, neighbor_colが範囲ないかのチェックも、WATERではないかのチェックと言えると思います。
なのでこれはまとめて関数化してしまうとわかりやすいと思います。下でやられていますね。
| num_rows = len(grid) | ||
| num_cols = len(grid[0]) | ||
| num_islands = 0 | ||
| directions = ((1, 0), (0, 1)) |
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.
BFSやDFSの場合近傍探索は上下左右が必要かと思います。例えばコの字型の島の場合左への遷移が必要です。
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.
レビューありがとうございます、それはその通りでした。directions = ((1, 0), (0, 1)) として良いのはDSUですね。
問題へのリンク
200. Number of Islands
言語
Python
step1
DFS を用いる解法。
DFSは、スタックの分だけの空間を使う上、Pythonでは再起呼び出し回数の制限がデフォルトでは1000と小さいので、パフォーマンス上はBFSを用いる方が望ましい。が、DFSの方がコードがシンプルになる場合が多い。
O(n*m)O(n*m)step2
seen_lands.add((row, column))をgrid[row][column] = "0"に変更することで、seen_landsの代わりに元のグリッドを利用でき、空間計算量をO(1)に削減できる。step3
step4 (FB)
別解・模範解答
BFS を用いる解法
bfs.pyDisjoint Set Union (Union-Find) を用いる解法
dsu.pyO(n*m*α(k))(αはアッカーマン関数の逆関数、kはunion/findの呼び出し回数)O(n*m)mydsu.pyは DSU をクラスとして実装した例。num_disjoint_setsを逐次管理することで、最後にルートの集合を数える計算を省略できる。想定されるフォローアップ質問
次に解く問題の予告