diff --git a/arai60/max-area-of-island/README.md b/arai60/max-area-of-island/README.md new file mode 100644 index 0000000..5abaf5e --- /dev/null +++ b/arai60/max-area-of-island/README.md @@ -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 diff --git a/arai60/max-area-of-island/step1.py b/arai60/max-area-of-island/step1.py new file mode 100644 index 0000000..ffa4cb6 --- /dev/null +++ b/arai60/max-area-of-island/step1.py @@ -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 = ( + 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) + for direction in range(4): + 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]: + max_area = max(max_area, calculate_area(i, j)) + return max_area diff --git a/arai60/max-area-of-island/step2_bfs.py b/arai60/max-area-of-island/step2_bfs.py new file mode 100644 index 0000000..86a137c --- /dev/null +++ b/arai60/max-area-of-island/step2_bfs.py @@ -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)]) + 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 + 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 diff --git a/arai60/max-area-of-island/step2_union_find.py b/arai60/max-area-of-island/step2_union_find.py new file mode 100644 index 0000000..987d9fa --- /dev/null +++ b/arai60/max-area-of-island/step2_union_find.py @@ -0,0 +1,55 @@ +class UnionFind: + 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) + 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 diff --git a/arai60/max-area-of-island/step3.py b/arai60/max-area-of-island/step3.py new file mode 100644 index 0000000..0365ebf --- /dev/null +++ b/arai60/max-area-of-island/step3.py @@ -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 = ( + 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) + for direction in range(4): + 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