题目:
给你一个下标从 0 开始的 m x n
整数矩阵 grid
。你一开始的位置在 左上角 格子 (0, 0)
。
当你在格子 (i, j)
的时候,你可以移动到以下格子之一:
- 满足
j < k <= grid[i][j] + j
的格子(i, k)
(向右移动),或者 - 满足
i < k <= grid[i][j] + i
的格子(k, j)
(向下移动)。
请你返回到达 右下角 格子 (m - 1, n - 1)
需要经过的最少移动格子数,如果无法到达右下角格子,请你返回 -1
。
思考:
1. 广度优先搜索
对每个点(i,j),判断向右和向下能直接到达的下一个点,把所有能到达的下一个点加入队列,然后进行下一轮判断。此处,为了不重复判断,设置一个矩阵记录每个点是否访问过,在将下一个点加入队列的同时,将其在矩阵中对应的值设为访问过。代码如下:
class Solution(object):
def minimumVisitedCells(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
from collections import deque
m, n = len(grid), len(grid[0])
visited = [[False for _ in range(n)] for _ in range(m)]
visited[0][0] = True
# 矩阵visited记录每个点是否访问过,避免重复判断
queue = deque([(0, 0, 1)]) # 需要判断的点组成的队列(i, j, steps)
while queue:
i, j, steps = queue.popleft() # 按先进先出原则依次判断队列中的点
if i == m - 1 and j == n - 1:
return steps # 若已经到达终点,则返回步数
# 遍历向右移动的情况
for k in range(j + 1, min(n, grid[i][j] + j + 1)):
# 这里的min(n, ...)是为了防止访问数组越界
if not visited[i][k]:
visited[i][k] = True
queue.append((i, k, steps + 1))
# 遍历向下移动的情况
for k in range(i + 1, min(m, i + grid[i][j] + 1)):
if not visited[k][j]:
visited[k][j] = True
queue.append((k, j, steps + 1))
return -1
熟悉的测试通过,提交超时又来了!!!!啊啊啊啊超时你这里欠我的拿什么还!!!:
2. 动态规划
然后考虑用动态规划做,用f[i][j]表示从 (i,j)到 (m−1,n−1)经过的最少格子数。设g = grid[i][j],方程为:
然后从(m-1, n-1)开始倒序遍历,最后返回f[0][0]的值。代码如下:
class Solution(object):
def minimumVisitedCells(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m, n = len(grid), len(grid[0])
dp = [[float('inf')] * n for _ in range(m)]
dp[m-1][n-1] = 1 # 初始化起点
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
g = grid[i][j]
# 向右移动
for k in range(j+1, min(j+g+1, n)):
dp[i][j] = min(dp[i][j], dp[i][k] + 1)
# 向下移动
for k in range(i+1, min(i+g+1, m)):
dp[i][j] = min(dp[i][j], dp[k][j] + 1)
if dp[0][0] != float('inf'):
return dp[0][0]
return -1
结果还是超时了。。。。。
3.维护每一行及每一列的优先队列
官方题解,贴一个代码在这,今天没看懂,有机会再看(python3):
class Solution:
def minimumVisitedCells(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
dist = [[-1] * n for _ in range(m)]
dist[0][0] = 1
row, col = [[] for _ in range(m)], [[] for _ in range(n)]
def update(x: int, y: int) -> int:
return y if x == -1 or y < x else x
for i in range(m):
for j in range(n):
while row[i] and row[i][0][1] + grid[i][row[i][0][1]] < j:
heapq.heappop(row[i])
if row[i]:
dist[i][j] = update(dist[i][j], dist[i][row[i][0][1]] + 1)
while col[j] and col[j][0][1] + grid[col[j][0][1]][j] < i:
heapq.heappop(col[j])
if col[j]:
dist[i][j] = update(dist[i][j], dist[col[j][0][1]][j] + 1)
if dist[i][j] != -1:
heapq.heappush(row[i], (dist[i][j], j))
heapq.heappush(col[j], (dist[i][j], i))
return dist[m - 1][n - 1]