diff --git a/200-Number-of-Islands/note.md b/200-Number-of-Islands/note.md new file mode 100644 index 0000000..fde1349 --- /dev/null +++ b/200-Number-of-Islands/note.md @@ -0,0 +1,39 @@ +# 200. Number of Islands + + + +## step1(まず通す) + +以下を繰り返せばいけそう: + +- 島を見つける→ 添え字順で見ていく。1があればそれが島の一部として島全体の範囲を確定させにいく +- 島を確定→1のマスに限定した幅優先探索をする。 +- カウントアップ + +## step2(整形&他の人のコードを読む) + +`find_whole_island` の中の for ループの前に `seen_nodes.add((row, column))` を書いてたがこれは while の外で1回だけ呼べばいい。 + +いろいろなチェックを2重ループで呼ぶと定数倍が重いので、最初に全部のノードを「まだ見てない」に詰めて、そこから pop する方がいい?と思ったが比較演算より set にする方が重いので元のままのほうがいいかも。 +実際、数人見た範囲では not_seen を用意している人はいなかった + +- + - 自分の実装だと row, column を表す変数名が複数出てきて混乱しやすそうと思っていたが、近傍のマス目を表す変数名として `neighbor` は良いと思った + - ただし今回はスコープも短いので自分の r,c という書き方でも良い気はしている +- + - 近傍のマス目自体を列挙する代わりに、移動量を列挙して `delta_row/delta_col` とするのもわかりやすい命名 + - ただし今回は条件式が長くなりやすいので個人的には近傍を列挙しておいて条件式はシンプルに書きたいと感じた + - 入力を破壊するかどうかの議論がある + - 綺麗に分類できるわけではないと思うが、自分の感覚としては + - 入力に対して何らかの変形を加えた同じ型のものを返す時はどちらでもあり得そう + - e.g. sort() メソッドと sorted() + - 入力に対して何らかの要約を与えるものは、破壊的だとちょっと驚くかも + - 入力について何かを数える、最大値、平均値 + - 今回は下だと思っている + - Python の代入は「名前(左辺)をオブジェクト(右辺)に束縛する」(オブジェクトに名前をラベル付けする)ことで、C 言語(やプログラミング一般)を勉強する時によくされる初心者向けの説明「変数という箱に中身を入れる」のメンタルモデルだと間違う +- + - 添字の範囲外チェックは(x が変数だとして) `x < head or tail <= x` みたいに書くよりは `not (head<= x < tail)` の方が見やすいだろう + - こうするならスッキリするので行と列の判定をまとめて良さそう + - ついでに、すでに見たかチェック→添字の範囲外チェックより逆の方がしっくりくる + +## step3(10分以内にさっとかける * 3回) diff --git a/200-Number-of-Islands/step1.py b/200-Number-of-Islands/step1.py new file mode 100644 index 0000000..6f7e0b7 --- /dev/null +++ b/200-Number-of-Islands/step1.py @@ -0,0 +1,37 @@ +from collections import deque + + +class Solution: + def numIslands(self, grid: list[list[str]]) -> int: + def find_whole_island(row: int, column: int): + nodes_to_see: deque[tuple[int, int]] = deque([(row, column)]) + while nodes_to_see: + node = nodes_to_see.popleft() + seen_nodes.add((row, column)) + for r, c in [ + (node[0], node[1] - 1), + (node[0], node[1] + 1), + (node[0] - 1, node[1]), + (node[0] + 1, node[1]), + ]: + if 0 <= r < num_rows and 0 <= c < num_columns: + if (r, c) not in seen_nodes and grid[r][c] == "1": + nodes_to_see.append((r, c)) + seen_nodes.add((r, c)) + + num_rows = len(grid) + num_columns = len(grid[0]) + seen_nodes: set[tuple[int, int]] = set() + num_islands = 0 + for r in range(num_rows): + for c in range(num_columns): + if grid[r][c] == "0": + seen_nodes.add((r, c)) + continue + if (r, c) in seen_nodes: + continue + + find_whole_island(r, c) + num_islands += 1 + + return num_islands diff --git a/200-Number-of-Islands/step2.py b/200-Number-of-Islands/step2.py new file mode 100644 index 0000000..cf03943 --- /dev/null +++ b/200-Number-of-Islands/step2.py @@ -0,0 +1,41 @@ +from collections import deque + + +class Solution: + def numIslands(self, grid: list[list[str]]) -> int: + def detect_whole_island(row: int, column: int): + nodes_to_see: deque[tuple[int, int]] = deque([(row, column)]) + seen_nodes.add((row, column)) + while nodes_to_see: + node = nodes_to_see.popleft() + for r, c in ( + (node[0], node[1] - 1), + (node[0], node[1] + 1), + (node[0] - 1, node[1]), + (node[0] + 1, node[1]), + ): + if not (0 <= r < num_rows and 0 <= c < num_columns): + continue + if (r, c) in seen_nodes: + continue + + if grid[r][c] == "1": + nodes_to_see.append((r, c)) + seen_nodes.add((r, c)) + + num_rows = len(grid) + num_columns = len(grid[0]) + seen_nodes: set[tuple[int, int]] = set() + num_islands = 0 + for row in range(num_rows): + for column in range(num_columns): + if (row, column) in seen_nodes: + continue + if grid[row][column] == "0": + seen_nodes.add((row, column)) + continue + + detect_whole_island(row, column) + num_islands += 1 + + return num_islands diff --git a/200-Number-of-Islands/step3.py b/200-Number-of-Islands/step3.py new file mode 100644 index 0000000..be9ae78 --- /dev/null +++ b/200-Number-of-Islands/step3.py @@ -0,0 +1,41 @@ +from collections import deque + + +class Solution: + def numIslands(self, grid: list[list[str]]) -> int: + def detect_whole_island(row: int, column: int): + nodes_to_see = deque([(row, column)]) + seen_nodes.add((row, column)) + while nodes_to_see: + node = nodes_to_see.popleft() + for r, c in ( + (node[0], node[1] - 1), + (node[0], node[1] + 1), + (node[0] - 1, node[1]), + (node[0] + 1, node[1]), + ): + if not (0 <= r < num_rows and 0 <= c < num_columns): + continue + if (r, c) in seen_nodes: + continue + + if grid[r][c] == "1": + nodes_to_see.append((r, c)) + seen_nodes.add((r, c)) + + num_rows = len(grid) + num_columns = len(grid[0]) + seen_nodes: set[tuple[int, int]] = set() + num_islands = 0 + for row in range(num_rows): + for column in range(num_columns): + if (row, column) in seen_nodes: + continue + if grid[row][column] == "0": + seen_nodes.add((row, column)) + continue + + detect_whole_island(row, column) + num_islands += 1 + + return num_islands