最小体力消耗路径

1. 题目

你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往  四个方向之一移动,你想要找到耗费 体力 最小的一条路径。

一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。

请你返回从左上角走到右下角的最小 体力消耗值 。

2. 示例

示例 1:

输入:heights = [[1,2,2],[3,8,2],[5,3,5]]
输出:2
解释:路径 [1,3,5,3,5] 连续格子的差值绝对值最大为 2 。
这条路径比路径 [1,2,2,2,5] 更优,因为另一条路径差值最大值为 3 。

示例 2:

输入:heights = [[1,2,3],[3,8,4],[5,3,5]]
输出:1
解释:路径 [1,2,3,4,5] 的相邻格子差值绝对值最大为 1 ,比路径 [1,3,5,3,5] 更优。

示例 3:

输入:heights = [[1,2,1,1,1],[1,2,1,2,1],[1,2,1,2,1],[1,2,1,2,1],[1,1,1,2,1]]
输出:0
解释:上图所示路径不需要消耗任何体力。

提示:

  • rows == heights.length
  • columns == heights[i].length
  • 1 <= rows, columns <= 100
  • 1 <= heights[i][j] <= 106

3. 思路

        这题我刚开始以为是动态规划的题目,因为这个和我之前做的一个题目很像,但看到第三个示例的图我才知道这是图搜索类型的题目,而说到图搜索,我们第一反应想到的是BFS(广度优先搜索)或DFS(深度优先搜索)这两种算法。因此这题我打算采用BFS算法;但是该如何进行BFS呢?

        首先,我们可以定义一个二元组列表,用来模拟上下左右移动,然后我们可以用二分查找算法来求最终的结果。这里就要提到为什么用二分查找,因为我们要查找最小体力消耗路径,而体力消耗是这条路径上最大的高度差,因此我们可以用一个x_0来定义当前路径最大允许的高度差,如果在该情况下可以到达终点,则说明结果ans <= x_0,即x_0大了,需要减少x_0的值;而如果不能到达终点,说明我们的x_0小了,需要增大x_0的值。因此这里我们可以用二分查找来寻找最小的x_0。

        然后在每次x_0(当前允许的最大高度差)的基础上,我们定义一个队列来实现BFS算法,我们将下一个移动的点加入队列的条件有哪些呢?

  • 0 <= x <= rows - 1
  • 0 <= y <= cols - 1
  • \left | heights[x][y] - height[new_x][new_y] \right | <= x_{0}
  • (new_x,new_y) 没有访问过

4. 代码

class Solution:
    def minimumEffortPath(self, heights: List[List[int]]) -> int:
        rows, columns = len(heights), len(heights[0])
        move = [(0, -1), (-1, 0), (0, 1), (1, 0)]  # 左上右下
        ans, left, right = 0, 0, 10 ** 6 - 1
        while left <= right:
            x_0 = (left + right) // 2    # 当前路线的最大允许高度差
            queue = [(0, 0)]    # 起点
            visited = {(0, 0), }    # 访问集合
            # 当队列不为空
            while queue:
                current = queue.pop(0)    # 出队
                # # 移动
                for x, y in move:
                    # 下一个点的x,y坐标
                    new_x, new_y = current[0] + x, current[1] + y
                    # 如果不在visited集合中 且 坐标合理 且 当前高度差小于允许高度差
                    if (new_x, new_y) not in visited and 0 <= new_x < rows and 0 <= new_y < columns and abs(
                            heights[current[0]][current[1]] - heights[new_x][new_y]) <= x_0:
                        queue.append((new_x, new_y))  # 加入队列
                        visited.add((new_x, new_y))    # 加入访问集合,之后不再访问
                # 如果到了最右下角则退出(终点)
                if current[0] == rows - 1 and current[1] == columns - 1:
                    ans = x_0    # 重置结果值
                    break
            # 如果当前路线可以到达终点
            if ans == x_0:
                right = x_0 - 1    # 减少右边界的值
            else:
                left = x_0 + 1    # 增加左边界的值
        return ans

    

5. 结果显示

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小人物₍˄·͈༝·͈˄*₎◞ ̑̑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值