Skip to content

Latest commit

 

History

History
145 lines (95 loc) · 5.1 KB

1631.path-with-minimum-effort.md

File metadata and controls

145 lines (95 loc) · 5.1 KB

题目地址(1631. 最小体力消耗路径)

https://leetcode-cn.com/problems/path-with-minimum-effort/

题目描述

你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。 一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。 请你返回从左上角走到右下角的最小 体力消耗值 。   示例 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] <= 10e6 

前置知识

公司

  • 暂无

思路

如果采用暴力解法, 需要找出所有的路径,然后返回最小代价的即可,时间复杂度是指数级别。回头看一下数据范围是 10e6,因此这种解法是不行的。

由于题目的解空间是 [0, 10**6 - 1]。

对解空间这个概念不熟悉的,可以看我之前的一篇题解686. 重复叠加字符串匹配

本质上,我们需要进行发问:

  • 0 可以么?
  • 1 可以么?
  • 2 可以么?
  • 。。。

直到找到第一个不可以的,我们返回前一个即可。

关于可不可以,我们可以使用 DFS 来做,由于只需要找到一条满足条件的,或者找到一个不满足的提前退出,因此最坏的情况是一直符合,并走到终点,这种情况下时间复杂度是 $(m \times n)$,因此总的时间复杂度是 $O(m \times n \times 10**6)$

实际上,上面的不断发问的过程不就是一个连续的递增序列么? 我们的目标不就是在一个连续递增序列找指定值么?于是二分法就不难想到。

而且这道题本质就是二分查找中的查找最右侧满足条件的值,关于这个问题,我已经在 【91 天学算法】二分查找 中进行了详细描述,并给出了代码模板,直接套就可以了。

值得注意的是,我们只需要找到一个满足条件的路径即可,因此可以利用短路剪枝。

returndfs(i+1, j, heights[i][j], target) ordfs(i-1, j, heights[i][j], target) ordfs(i, j+1, heights[i][j], target) ordfs(i, j-1, heights[i][j], target)

而不是写出下面的代码(下面的代码会超时):

top=dfs(i+1, j, heights[i][j], target) bottom=dfs(i-1, j, heights[i][j], target) right=dfs(i, j+1, heights[i][j], target) left=dfs(i, j-1, heights[i][j], target) returntoporbottomorrightorleft

代码

代码支持:Python3

classSolution: defminimumEffortPath(self, heights: List[List[int]]) ->int: lo, hi=0, 10**6-1m, n=len(heights), len(heights[0]) defdfs(i, j, pre, target): if (i, j) invisited: returnFalseifi<0ori>=morj<0orj>=norabs(heights[i][j] -pre) >target: returnFalseifi==m-1andj==n-1: returnTruevisited.add((i, j)) returndfs(i+1, j, heights[i][j], target) ordfs(i-1, j, heights[i][j], target) ordfs(i, j+1, heights[i][j], target) ordfs(i, j-1, heights[i][j], target) # 查找最右侧满足条件的值whilelo<=hi: visited=set() mid= (lo+hi) >>1ifdfs(0, 0, heights[0][0], mid): hi=mid-1else: lo=mid+1returnlo

复杂度分析

m 为 矩阵的高度, n 为矩阵的长度。

  • 时间复杂度:$O(4 \times m \times n \times log_2 10^6)$,其中 $log_2 10^6$ 为二分的次数, $4 \times m \times n$ 为每次 dfs 的时间。
  • 空间复杂度:$O(m \times n)$,不管是递归的栈开销还是 visited 的开销都是 $O(m \times n)$

相关问题

close