diff --git a/0778.Swim-in-Rising-Water/memo.md b/0778.Swim-in-Rising-Water/memo.md new file mode 100644 index 0000000..bf2a7c0 --- /dev/null +++ b/0778.Swim-in-Rising-Water/memo.md @@ -0,0 +1,22 @@ +# 778. Swim in Rising Water + +## step1 +自力で二分探索を思いつくことができた。計算量 O(n^2 logn)。 + +時間 t と grid の値の不等号の向きを間違えて時間を溶かした。21m。 + +## step2 + +> Use either Dijkstra's, or binary search for the best time T for which you can reach the end if you only step on squares at most T. + +Dijkstraを使うのか。和ではなくmaxをcostの計算に使えばよい。こちらも計算量O(n^2 logn)。 + +BFSを毎回行う二分探索よりも定数倍速い。 + +--- +https://leetcode.com/problems/swim-in-rising-water/solutions/7252184/swim-in-rising-water-3-approach-editoria-8zp6/?envType=problem-list-v2&envId=7p55wqm + +Union-Find + Kruskal + +## step3 +TODO: Kruskal法を書く diff --git a/0778.Swim-in-Rising-Water/step1_binary_search.py b/0778.Swim-in-Rising-Water/step1_binary_search.py new file mode 100644 index 0000000..e6116c6 --- /dev/null +++ b/0778.Swim-in-Rising-Water/step1_binary_search.py @@ -0,0 +1,44 @@ +class Solution: + def swimInWater(self, grid: list[list[int]]) -> int: + if not grid or not grid[0]: + return 0 + if len(grid) != len(grid[0]): + raise ValueError("invalid grid") + + n = len(grid) + + def can_reach_within(t): + if grid[0][0] > t: + return False + + reachable = [(0, 0)] + seen = set((0, 0)) + while reachable: + next_reachable = [] + for r, c in reachable: + if r == n - 1 and c == n - 1: + return True + for r_next, c_next in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)): + if not (0 <= r_next < n and 0 <= c_next < n): + continue + if (r_next, c_next) in seen or grid[r_next][c_next] > t: + continue + seen.add((r_next, c_next)) + next_reachable.append((r_next, c_next)) + reachable = next_reachable + + return False + + + left = 0 + right = n * n - 1 + while left < right: + mid = (left + right) // 2 + if not can_reach_within(mid): + left = mid + 1 + else: + right = mid + + return left + + diff --git a/0778.Swim-in-Rising-Water/step2_dijkstra.py b/0778.Swim-in-Rising-Water/step2_dijkstra.py new file mode 100644 index 0000000..94de637 --- /dev/null +++ b/0778.Swim-in-Rising-Water/step2_dijkstra.py @@ -0,0 +1,27 @@ +import heapq + +class Solution: + def swimInWater(self, grid: list[list[int]]) -> int: + if not grid or not grid[0]: + return 0 + if len(grid) != len(grid[0]): + raise ValueError("invalid grid") + + n = len(grid) + heap = [(grid[0][0], 0, 0)] + costs = [n * n] * (n * n) + costs[0] = grid[0][0] + + while heap: + cost, r, c = heapq.heappop(heap) + if r == n - 1 and c == n - 1: + return cost + + for r_next, c_next in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)): + if not (0 <= r_next < n and 0 <= c_next < n): + continue + cost_next = max(cost, grid[r_next][c_next]) + if cost_next < costs[r_next * n + c_next]: + costs[r_next * n + c_next] = cost_next + heapq.heappush(heap, (cost_next, r_next, c_next)) + diff --git a/0778.Swim-in-Rising-Water/step2_dijkstra_revised.py b/0778.Swim-in-Rising-Water/step2_dijkstra_revised.py new file mode 100644 index 0000000..39354cb --- /dev/null +++ b/0778.Swim-in-Rising-Water/step2_dijkstra_revised.py @@ -0,0 +1,27 @@ +import heapq + +class Solution: + def swimInWater(self, grid: list[list[int]]) -> int: + if not grid or not grid[0]: + return 0 + if len(grid) != len(grid[0]): + raise ValueError("invalid grid") + + n = len(grid) + candidate_cells = [(grid[0][0], 0, 0)] + costs = [n * n] * (n * n) + costs[0] = grid[0][0] + + while candidate_cells: + cost, r, c = heapq.heappop(candidate_cells) + if r == n - 1 and c == n - 1: + return cost + + for r_next, c_next in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)): + if not (0 <= r_next < n and 0 <= c_next < n): + continue + cost_next = max(cost, grid[r_next][c_next]) + if cost_next < costs[r_next * n + c_next]: + costs[r_next * n + c_next] = cost_next + heapq.heappush(candidate_cells, (cost_next, r_next, c_next)) + diff --git a/0778.Swim-in-Rising-Water/step2_union_find.py b/0778.Swim-in-Rising-Water/step2_union_find.py new file mode 100644 index 0000000..124e862 --- /dev/null +++ b/0778.Swim-in-Rising-Water/step2_union_find.py @@ -0,0 +1,50 @@ +class UnionFind: + def __init__(self, n): + self.parent = list(range(n)) + + def find(self, i): + if self.parent[i] == i: + return i + self.parent[i] = self.find(self.parent[i]) + return self.parent[i] + + def union(self, i, j): + root_i = self.find(i) + root_j = self.find(j) + if root_i != root_j: + self.parent[root_i] = root_j + return True + return False + + +class Solution: + def swimInWater(self, grid: list[list[int]]) -> int: + if not grid or not grid[0]: + return 0 + if len(grid) != len(grid[0]): + raise ValueError("invalid grid") + if len(grid) == 1: + return grid[0][0] + + n = len(grid) + + edges = [] + for r in range(n): + for c in range(n): + if r + 1 < n: + cost = max(grid[r][c], grid[r + 1][c]) + edges.append((cost, r * n + c, (r + 1)* n + c)) + if c + 1 < n: + cost = max(grid[r][c], grid[r][c + 1]) + edges.append((cost, r * n + c, r * n + c + 1)) + + edges.sort() + + uf = UnionFind(n * n) + + for cost, u, v in edges: + uf.union(u, v) + if uf.find(0) == uf.find((n - 1) * n + n - 1): + return cost + + return -1