You are a hiker preparing for an upcoming hike. You are given heights, a 2D array of size rows x columns, where heights[row][col] represents the height of cell (row, col). You are situated in the top-left cell, (0, 0), and you hope to travel to the bottom-right cell, (rows-1, columns-1) (i.e., 0-indexed). You can move up, down, left, or right, and you wish to find a route that requires the minimum effort.
A route’s effort is the maximum absolute difference in heights between two consecutive cells of the route.
Return the minimum effort required to travel from the top-left cell to the bottom-right cell.
Input:
heights = [[1,2,2],[3,8,2],[5,3,5]]
Output:
2
Explanation: The route of [1,3,5,3,5] has a maximum absolute difference of 2 in consecutive cells.
This is better than the route of [1,2,2,2,5], where the maximum absolute difference is 3.
Example 2:
1
2
3
4
5
Input:
heights = [[1,2,3],[3,8,4],[5,3,5]]
Output:
1
Explanation: The route of [1,2,3,4,5] has a maximum absolute difference of 1 in consecutive cells, which is better than route [1,3,5,3,5].
Example 3:
1
2
3
4
5
Input:
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]]
Output:
0
Explanation: This route does not require any effort.
The key idea is to use Dijkstra’s algorithm to always expand the path with the minimum current effort (maximum height difference so far). This ensures that when we reach the bottom-right cell, the effort is minimized.
classSolution {
public:int minimumEffortPath(vector<vector<int>>& heights) {
int m = heights.size(), n = heights[0].size();
vector<vector<int>> effort(m, vector<int>(n, INT_MAX));
effort[0][0] =0;
priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, greater<>> pq;
pq.emplace(0, 0, 0);
int dirs[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
while (!pq.empty()) {
auto [e, i, j] = pq.top(); pq.pop();
if (i == m-1&& j == n-1) return e;
for (auto& d : dirs) {
int x = i + d[0], y = j + d[1];
if (x >=0&& x < m && y >=0&& y < n) {
int ne = max(e, abs(heights[i][j] - heights[x][y]));
if (ne < effort[x][y]) {
effort[x][y] = ne;
pq.emplace(ne, x, y);
}
}
}
}
return0;
}
};
classSolution {
publicintminimumEffortPath(int[][] heights) {
int m = heights.length, n = heights[0].length;
int[][] effort =newint[m][n];
for (int[] row : effort) Arrays.fill(row, Integer.MAX_VALUE);
effort[0][0]= 0;
PriorityQueue<int[]> pq =new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
pq.offer(newint[]{0, 0, 0});
int[][] dirs = {{0,1},{1,0},{0,-1},{-1,0}};
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int e = cur[0], i = cur[1], j = cur[2];
if (i == m-1 && j == n-1) return e;
for (int[] d : dirs) {
int x = i + d[0], y = j + d[1];
if (x >= 0 && x < m && y >= 0 && y < n) {
int ne = Math.max(e, Math.abs(heights[i][j]- heights[x][y]));
if (ne < effort[x][y]) {
effort[x][y]= ne;
pq.offer(newint[]{ne, x, y});
}
}
}
}
return 0;
}
}
classSolution {
funminimumEffortPath(heights: Array<IntArray>): Int {
val m = heights.size
val n = heights[0].size
val effort = Array(m) { IntArray(n) { Int.MAX_VALUE } }
effort[0][0] = 0val pq = java.util.PriorityQueue(compareBy<IntArray> { it[0] })
pq.add(intArrayOf(0, 0, 0))
val dirs = arrayOf(0 to 1, 1 to 0, 0 to -1, -1 to 0)
while (pq.isNotEmpty()) {
val(e, i, j) = pq.remove()
if (i == m-1&& j == n-1) return e
for ((dx, dy) in dirs) {
val x = i + dx
val y = j + dy
if (x in0 until m && y in0 until n) {
val ne = maxOf(e, kotlin.math.abs(heights[i][j] - heights[x][y]))
if (ne < effort[x][y]) {
effort[x][y] = ne
pq.add(intArrayOf(ne, x, y))
}
}
}
}
return0 }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classSolution:
defminimumEffortPath(self, heights: list[list[int]]) -> int:
import heapq
m, n = len(heights), len(heights[0])
effort = [[float('inf')] * n for _ in range(m)]
effort[0][0] =0 h = [(0, 0, 0)]
while h:
e, i, j = heapq.heappop(h)
if i == m-1and j == n-1:
return e
for dx, dy in ((0,1),(1,0),(0,-1),(-1,0)):
x, y = i+dx, j+dy
if0<= x < m and0<= y < n:
ne = max(e, abs(heights[i][j] - heights[x][y]))
if ne < effort[x][y]:
effort[x][y] = ne
heapq.heappush(h, (ne, x, y))
return0
impl Solution {
pubfnminimum_effort_path(heights: Vec<Vec<i32>>) -> i32 {
use std::collections::BinaryHeap;
let m = heights.len();
let n = heights[0].len();
letmut effort =vec![vec![i32::MAX; n]; m];
effort[0][0] =0;
letmut h = BinaryHeap::new();
h.push((0, 0, 0));
let dirs = [(0,1),(1,0),(0,-1),(-1,0)];
whilelet Some((e, i, j)) = h.pop() {
let e =-e;
if i == m-1&& j == n-1 { return e; }
for (dx, dy) in dirs.iter() {
let x = i asi32+ dx;
let y = j asi32+ dy;
if x >=0&& x < m asi32&& y >=0&& y < n asi32 {
let (x, y) = (x asusize, y asusize);
let ne = effort[i][j].max((heights[i][j] - heights[x][y]).abs());
if ne < effort[x][y] {
effort[x][y] = ne;
h.push((-ne, x, y));
}
}
}
}
0 }
}