Leetcode 1102:得分最高的路径(超详细的解法!!!)

给你一个 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. 1 <= R, C <= 100
  2. 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

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值