解题思路
这个问题第一感还是BFS (breath frist search),对BFS还不了解的可以看我的另一篇博客。只是每个点上要记住自己的count, 和还剩多少可以用的障碍。不过在这里面有一个问题:有可能一个点有几个路径经过,而且这些路径对应着不同的count和不同的可用障碍(k)。
一般来说,由于在BFS中,一旦经历过某节点,我不需要回溯,所以才用set的方式来进行记录,在这个问题中,由于可能会记录一个节点的几个情况,就不能用set了。
这时候就用一个跟原图一样的map,由于我们采用BFS,保证了之后的count一定大于等于之前的count;这样子再碰到某节点时,我们可以将节点信息更新为可能更小的k数字(反之如果有更大的k, 更小的count成功,之前的neighbor一定已经返回了)。
代码
def shortestPath(self, grid: List[List[int]], k: int) -> int:
if len(grid) == 1 and len(grid[0]) == 1:
return 0
current = deque([((0,0), k, 0)])
# remaining is same of grid with -1
remaining[0][0] = k
while current:
node, wall, count = current.popleft()
for n_node in neighbor(node[0], node[1], len(grid), len(grid[0])):
if n_node == (len(grid)-1, len(grid[0])-1):
return count + 1
if wall - grid[n_node[0]][n_node[1]] > remaining[n_node[0]][n_node[1]]:
current.append((n_node, wall - grid[n_node[0]][n_node[1]], count+1))
remaining[n_node[0]][n_node[1]] = wall - grid[n_node[0]][n_node[1]]
return -1
这里面省略了remaining matrix的初始化以及如何计算neighbor。
讨论
- 我很少用到visited nodes不用set表示的情况,所以我觉得这个例子还是很有趣的 (also classified as a hard problem)
- 执行的时候同一个点先算count小的部分,然后一边count小的去看能不能到终点,另一方面看看有没有更少障碍;这两个部分同时在计算而互不影响,感觉像是一个很巧妙的async执行,竟然还有点美感 :)