LC 2577. 在网格图中访问一个格子的最少时间
https://leetcode.cn/problems/minimum-time-to-visit-a-cell-in-a-grid/
这题一个关键是,如果向相邻格子前进如果不满足条件的话,那么可以在过去路径上的两格来回走,每次+2.
其实这个就是格点上的奇偶性问题,并且这个是可以归纳出来的:
- (0, 0) 上的奇偶性是0
- 假设(x,y)上奇偶性是a的话,那么(x+1,y)或者是(x,y+1)就是1-a
- 所以在(x,y)上需要round一下.
想清楚这个思路的之后就是dijkstra最短路搜索了。
class Solution: def minimumTime(self, grid: List[List[int]]) -> int: n, m = len(grid), len(grid[0]) if grid[0][1] > 1 and grid[1][0] > 1: return -1 hp = [] hp.append((0, 0, 0)) inf = 1 << 30 visit = [[inf] * m for _ in range(n)] import heapq while hp: (d, x, y) = heapq.heappop(hp) if (x, y) == (n - 1, m - 1): return d for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)): x2, y2 = x + dx, y + dy if 0 <= x2 < n and 0 <= y2 < m: gap = grid[x2][y2] - (d + 1) if gap <= 0: value = d + 1 else: value0 = d + 1 + (gap + 1) // 2 * 2 # 也可以是下面这种形式 value1 = grid[x2][y2] + (grid[x2][y2] - x2 - y2) % 2 value = value0 if visit[x2][y2] > value: visit[x2][y2] = value heapq.heappush(hp, (value, x2, y2)) return -1
我觉得这个 题解 里面提到的二分方法也比较对,但是没有搞清楚为什么不work. 差别在于二分方式上,看上去需要确保解上有1个位置的空间 `left + 1 <= right`. 然后选择right.
我觉得这个解法里面vis特别巧妙,使用 `checktime` 来判断是否已经访问过,这样可以复用之前整个数组。
class Solution: def minimumTime(self, grid: List[List[int]]) -> int: n, m = len(grid), len(grid[0]) if grid[0][1] > 1 and grid[1][0] > 1: return -1 # 将vis放在外面特别好,因为每次vis time是不同的 vis = [[0] * m for _ in range(n)] def test(T): vis[-1][-1] = T from collections import deque dq = deque() dq.append((T, n - 1, m - 1)) while dq: (t, x, y) = dq.popleft() if (x, y) == (0, 0): return True for dx, dy in ((-1, 0), (1, 0), (0, -1), (0, 1)): x2, y2 = x + dx, y + dy if 0 <= x2 < n and 0 <= y2 < m and vis[x2][y2] != T and grid[x2][y2] <= (t - 1): vis[x2][y2] = T dq.append((t - 1, x2, y2)) return False left = max(grid[-1][-1], m + n - 2) - 1 right = max(map(max, grid)) + m + n while (left + 1) < right: t = (left + right) // 2 if test(t): right = t else: left = t + 1 ans = right ans = ans + (ans - m - n) % 2 return ans