【力扣roadmap】2812. 找出最安全路径

10 阅读2分钟

题目描述

image.png

思路分析

WA了几发。我现在才知道,list.pop默认是pop(-1),弹出的末尾元素,我一直以为弹出的是队首(手动捂脸哭)

审题,找找思路:

  1. 题目涉及到:每条路径的安全系数用路径任意位置距离任意小偷最小距离定义。且全部的路径全局最大的安全距离是多少。这种最小最大同时出现的问题,你知道应用使用二分查找。
  2. 有多个小偷,需要知道每个位置距离最近的小偷的距离,需要使用多源bfs

本题做法如下

  1. 使用多源bfs,将所有小偷加入队列,然后bfs。cost_grid[nx][ny] == inf 意味着这个位置没被遍历且无小偷,这个条件等价于(nx,ny) not in vis and grid[nx][ny] == 0

  2. 二分安全系数safe,查看在当前safe下,能否从起点走到终点。(给定safe,任何低于safe的方块都是禁入点,基于此使用bfs判断可达性)

  3. 最后提一下这个二分模板,这是一个upper_bound模板,找到第一个非法位置需要减一才是最后一个合法位置。

代码

class Solution:
    def maximumSafenessFactor(self, grid: List[List[int]]) -> int:
        n = len(grid)
        if grid[0][0] == 1 or grid[n-1][n-1] == 1:
            return 0
        cost_grid = [[inf] * n for _ in range(n)] 
        q = deque()
        for i in range(n) :
            for j in range(n) :
                if grid[i][j] == 1 :
                    q.append((i,j))
                    cost_grid[i][j] = 0 
        dx = [0,0,1,-1]
        dy = [1,-1,0,0] 
        while q :
            cur_x,cur_y = q.popleft()
            for i in range(4):
                nx , ny = cur_x + dx[i] , cur_y + dy[i] 
                if nx >= 0 and nx < n and ny >= 0 and ny < n and cost_grid[nx][ny] is inf:
                    q.append((nx,ny))
                    cost_grid[nx][ny] = cost_grid[cur_x][cur_y] + 1
        # 二分
        def check(safe: int) -> bool:
            # 起点安全系数不足,直接不可行
            if cost_grid[0][0] < safe:
                return False
            vis = [[False] * n for _ in range(n)]
            q = deque()
            q.append((0, 0))
            vis[0][0] = True
            while q:
                cur_x, cur_y = q.popleft()
                # 到达终点,可行
                if cur_x == n-1 and cur_y == n-1:
                    return True
                for i in range(4):
                    nx, ny = cur_x + dx[i], cur_y + dy[i]
                    # 边界、未访问、安全系数达标
                    if 0 <= nx < n and 0 <= ny < n and not vis[nx][ny] and cost_grid[nx][ny] >= safe:
                        vis[nx][ny] = True
                        q.append((nx, ny))
            return False
        
        l , r = 0 , n + n - 1
        while l < r :
            mid = (l + r) >> 1 
            # 然后利用mid判断是否可以从左上到右下
            if check(mid) :
                l = mid + 1
            else :
                r = mid 
        return l - 1