给你一个 R 行 C 列的整数矩阵 A
。矩阵上的路径从 [0,0]
开始,在 [R-1,C-1]
结束。
路径沿四个基本方向(上、下、左、右)展开,从一个已访问单元格移动到任一相邻的未访问单元格。
路径的得分是该路径上的 最小 值。例如,路径 8 → 4 → 5 → 9 的值为 4 。
找出所有路径中得分 最高 的那条路径,返回其 得分。
示例 1:
输入:[[5,4,5],[1,2,6],[7,4,6]]
输出:4
解释:
得分最高的路径用黄色突出显示。
示例 2:
输入:[[2,2,1,2,2,2],[1,2,2,2,1,2]]
输出:2
示例 3:
输入:[[3,4,6,3,4],[0,2,1,1,7],[8,8,3,2,7],[3,2,4,9,8],[4,1,2,0,0],[4,6,5,4,3]]
输出:3
提示:
1 <= R, C <= 100
0 <= A[i][j] <= 10^9
解题思路
首先这个问题不难想到dfs
,我们很容易就写出下面的代码
class Solution:
def maximumMinimumPath(self, A: List[List[int]]) -> int:
dire = [[1, 0], [-1, 0], [0, 1], [0, -1]]
r, c, res = len(A), len(A[0]), 0
vi = [[0] * c for _ in range(r)]
def dfs(x, y, t):
nonlocal res
if x == r-1 and y == c-1:
res = max(res, t)
return
for i, j in dire:
nx, ny = i + x, j + y
if nx >= 0 and nx < r and ny >= 0 and ny < c and vi[nx][ny] == 0:
vi[nx][ny] = 1
dfs(nx, ny, min(t, A[nx][ny]))
vi[nx][ny] = 0
vi[0][0] = 1
dfs(0, 0, A[0][0])
return res
好的,不出意外,我们会得到超时的提示,_。我们需要优化它,首先不难想到下面这不优化
def dfs(x, y, t):
nonlocal res
if t < res:
return
当我们知道最小的元素比res
都小的话,那么自然不用继续遍历了。接着提交,还是会超时,继续优化。
我们知道,如果我们想要最后的得分最高,那么我们每一步都尽量走最高的分数(贪心)。由于每次都是去周边得分的最大值,所以不难想到使用排序或者最大堆(我这里使用了最大堆)
import heapq
class Solution:
def maximumMinimumPath(self, A: List[List[int]]) -> int:
dire = [[1, 0], [-1, 0], [0, 1], [0, -1]]
r, c, res = len(A), len(A[0]), 0
vi = [[0] * c for _ in range(r)]
h = [[-A[0][0], 0, 0]]
heapq.heapify(h)
def dfs():
nonlocal res
pre, x, y = heapq.heappop(h)
if x == r-1 and y == c-1:
res = max(res, -pre)
return
for i, j in dire:
nx, ny = i + x, j + y
if nx >= 0 and nx < r and ny >= 0 and ny < c and vi[nx][ny] == 0:
vi[nx][ny] = 1
heapq.heappush(h, [max(pre, -A[nx][ny]), nx, ny])
dfs()
vi[0][0] = 1
dfs()
return res
你这个时候一定会困惑,难道每次选最大的就一定可以有解吗?当然不一定,但是如果最大的情况没有的话,那么我们只要考虑次大的有没有即可,也就是我们要保证每次遍历的情况都是最优的。
这个问题还有一个非常好的思路,就是通过二分法。二分法的关键就是我们需要写一个判定函数,我们如何去判定一个路径中的元素不小于t
的情况下是合法的?使用bfs
搜索是不是有小于t
的元素即可。
class Solution:
def maximumMinimumPath(self, A: List[List[int]]) -> int:
dire = [[1, 0], [-1, 0], [0, 1], [0, -1]]
row, col = len(A), len(A[0])
def check(ok):
if A[0][0] < ok:
return 0
vi = [[0] * col for _ in range(row)]
vi[0][0] = 1
q = [(0, 0)]
while q:
x, y = q.pop(0)
for i, j in dire:
nx, ny = x + i, y + j
if nx >= 0 and nx < row and ny >= 0 and ny < col \
and vi[nx][ny] == 0 and A[nx][ny] >= ok:
vi[nx][ny] = 1
q.append((nx, ny))
return vi[-1][-1]
l, r = 0, max([max(i) for i in A])
while l < r:
mid = (l + r + 1) >> 1
if check(mid):
l = mid
else:
r = mid - 1
return l
但是这种做法的话,使用python
提交会超时,使用cpp
不会。
这个问题还可以通过排序加并查集来解,但是实际思想和第一种使用最大堆的思路类似。由于代码比较复杂,我就不再谈它。
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!