Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions 0778.Swim-in-Rising-Water/memo.md
Original file line number Diff line number Diff line change
@@ -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法を書く
44 changes: 44 additions & 0 deletions 0778.Swim-in-Rising-Water/step1_binary_search.py
Original file line number Diff line number Diff line change
@@ -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


27 changes: 27 additions & 0 deletions 0778.Swim-in-Rising-Water/step2_dijkstra.py
Original file line number Diff line number Diff line change
@@ -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)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらのコメントをご参照ください。
rimokem/arai60#25 (comment)

candidates や frontier はいかがでしょうか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

そうですね、具体的になるようにcandidate_cellsとしました

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))

27 changes: 27 additions & 0 deletions 0778.Swim-in-Rising-Water/step2_dijkstra_revised.py
Original file line number Diff line number Diff line change
@@ -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))

50 changes: 50 additions & 0 deletions 0778.Swim-in-Rising-Water/step2_union_find.py
Original file line number Diff line number Diff line change
@@ -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