Leetcode # 2812. Find the Safest Path in a Grid
https://leetcode.com/contest/weekly-contest-357/problems/find-the-safest-path-in-a-grid/
Solution
計算 min_dis (queue/BFS)
m := len(grid)
n := len(grid[0])
min_dis[i][j] := min([manhattan_distance((i, j), thief) for thief in thieves])
以 (i, j) 為起點,計算整張 grid 的 min_dis[i][j]
for i in range(m):
for j in range(n):
compute min_dis[i][j]
time complexity:O(m * n * len(thieves))
使用 queue/BFS 以 thieves 為起點遍歷整張 grid
time complexity: O(m * n)
找到 maximum safeness factor 的 path
safeness factor := min([min_dis[i][j] for i, j in path])
目標:Return the maximum safeness factor of all paths from (0, 0) to (m – 1, n – 1)
找出 max([min_dis[i][j] for i, j in path]) 最小的 path
找出 sum([min_dis[i][j] for i, j in path]) 最小的 path
從 (0, 0) 走到 (m, n) 只會向右或向下走
正確的 path 找法:
1. 走法可以任意上下左右
2. 令 maximum safeness factor 為 d
⇒ 找不到一條 any(min_dis[i][j] > d for i, j in path) == True 的path
⇔ all(min_dis[i][j] <= d for path in paths for i, j in path)
⇔ 最遠只能和 thieves 保持距離 d 以下(⇒ d 越大越困難)
寫一個can_find_a_path(safeness_factor_greater_than)
(time complexity: O(m * n))
能用來判斷能不能找到
all(min_dis[i][j] > safeness_factor_greater_than
for i, j in path) == True 的path
再用 binary search 找出能使can_find_a_path(d)
為False
的d
因為 d 越大越困難,我們要找的 d 能滿足:
1. all(can_find_a_path(_d) == True for _d in range(d)) == True
2. all(can_find_a_path(_d) == False for _d in range(d, m + n + 1)) == True
Time Complexity: O((m * n) + (m * n) * log(m + n)) = O(m * n * log(m + n))
Space Complexity: O(m * n)
(The input and output generally do not count towards the space complexity.)
class Solution: def maximumSafenessFactor(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) direct = [(0, 1), (0, -1), (1, 0), (-1, 0)] manhattan = lambda a, b, x, y: abs(a - x) + abs(b - y) thieves = [(j, i, 0) for i in range(m) for j in range(n) if grid[i][j] == 1] min_dis = [[None] * n for _ in range(m)] queue = collections.deque(thieves) while queue: j, i, dis = queue.popleft() if min_dis[i][j] is not None: continue min_dis[i][j] = dis for dr in direct: _i, _j = i + dr[1], j + dr[0] if 0 <= _i < m and 0 <= _j < n: queue.append((_j, _i, dis + 1)) def can_find_a_path(safeness_factor_greater_than): footprint = [[False] * n for _ in range(m)] def goto(i, j): footprint[i][j] = True if min_dis[i][j] <= safeness_factor_greater_than: return False if i == m - 1 and j == n - 1: return True for dr in direct: _i, _j = i + dr[1], j + dr[0] if 0 <= _i < m and 0 <= _j < n and not footprint[_i][_j]: if goto(_i, _j): return True return False return goto(0, 0) left, right = 0, (m + n) while left < right: mid = (left + right) // 2 result = can_find_a_path(mid) if result: left = mid + 1 else: right = mid return left
Last Updated on 2023/09/09 by A1go