Leetcode 1293:网格中的最短路径(超详细的解法!!!)

本文探讨了一个关于在带有障碍物的网格中寻找最短路径的问题。通过使用广度优先搜索(BFS)算法,文章详细阐述了解决方案,特别关注如何在允许消除一定数量障碍物的情况下找到从左上角到右下角的最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个 m * n 的网格,其中每个单元格不是 0(空)就是 1(障碍物)。每一步,您都可以在空白单元格中上、下、左、右移动。

如果您 最多 可以消除 k 个障碍物,请找出从左上角 (0, 0) 到右下角 (m-1, n-1) 的最短路径,并返回通过该路径所需的步数。如果找不到这样的路径,则返回 -1。

示例 1:

输入: 
grid = 
[[0,0,0],
 [1,1,0],
 [0,0,0],
 [0,1,1],
 [0,0,0]], 
k = 1
输出:6
解释:
不消除任何障碍的最短路径是 10。
消除位置 (3,2) 处的障碍后,最短路径是 6 。该路径是 (0,0) -> (0,1) -> (0,2) -> (1,2) -> (2,2) -> (3,2) -> (4,2). 

示例 2:

输入:
grid = 
[[0,1,1],
 [1,1,1],
 [1,0,0]], 
k = 1
输出:-1
解释:
我们至少需要消除两个障碍才能找到这样的路径。 

提示:

  • grid.length == m
  • grid[0].length == n
  • 1 <= m, n <= 40
  • 1 <= k <= m*n
  • grid[i][j] == 0 or 1
  • grid[0][0] == grid[m-1][n-1] == 0

解题思路

最短路经问题直接使用bfs,需要注意的是遍历的过程中记录的访问节点。传统的bfs记录横纵坐标即可,但是这个问题多个了参数k,所以我们还需记录k的数值。这里有两种方案,一种是采用set记录(x,y,k),另一种是通过dict记录key:(x,y)value:k(我这里使用第二种)。

如果采用第一种方案的话,就是最原始的写法,只要判断(x,y,k)是不是之前访问过即可;但如果采用第二种写法的话,我们就需要判断原来(x,y)的值k1(初始状态为inf)比当前遍历到的(x,y)的值k2小,那么需要将原来的k1更新为k2

如果k>=r+c-3的话,那么就算是所有网络都是1,我们也可以在r+c-2的步数内实现。

class Solution:
    def shortestPath(self, g: List[List[int]], k: int) -> int:
        r, c = len(g), len(g[0])
        if k >= r + c - 3:
            return r + c -2
        
        mem = {(0, 0):0}
        q, step = [(0, 0, 0)], 0
        
        while q:
            n = len(q)
            for _ in range(n):
                x, y, pre = q.pop(0)
                if pre > k: 
                    continue
                    
                if x == r - 1 and y == c - 1:
                    return step
                
                for i, j in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                    nx, ny = x + i, y + j
                    if 0 <= nx < r and 0 <= ny < c:
                        nPre = pre + 1 if g[nx][ny] == 1 else pre
                        if nPre < mem.get((nx, ny), float("inf")):
                            q.append((nx, ny, nPre))
                            mem[(nx, ny)] = nPre
            step += 1
        return -1

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值