LeetCode #1631 Medium

Path With Minimum Effort

Given a 2D grid heights of size m x n, find a path from the top-left to the bottom-right that minimises the maximum absolute difference in heights between adjacent cells along the path.

graphsbinary-searchheapbfs
Open on LeetCode ↗
02

Intuition

This is not a shortest-path problem in the usual sense — you are minimising the maximum edge weight along a path, not the sum. But Dijkstra's algorithm still works: use a min-heap where the priority is the maximum effort seen so far on the path to that cell. Always expand the cell reachable with the smallest bottleneck effort. The first time you reach the bottom-right corner, that effort is the answer — because any other path would have a bottleneck at least as large (Dijkstra's greedy property applies to bottleneck paths too).

How to spot this pattern

The signal is 'minimise the maximum step along any path in a grid'. This is a bottleneck shortest path, and Dijkstra (or binary search + BFS) handles it. Any time a path's cost is defined by its worst edge rather than the sum of edges, the same modified Dijkstra applies — push max(current, edge) instead of current + edge.

03

Approach

1

Model the grid as a graph with effort-based edge weights

Each cell is a node. An edge connects adjacent cells (up, down, left, right) with weight abs(heights[r1][c1] - heights[r2][c2]). The path cost is the maximum edge weight along the path, not the sum.

2

Run modified Dijkstra with a min-heap on bottleneck effort

Push (0, 0, 0) — effort 0, starting at (0, 0). Maintain a dist array where dist[r][c] is the minimum bottleneck effort to reach (r, c). Pop the smallest-effort cell. For each neighbor, compute the effort of using this edge: max(current_effort, abs(heights[r][c] - heights[nr][nc])). If this is less than dist[nr][nc], update and push.

3

Return the effort when the bottom-right corner is reached

The first time (m-1, n-1) is popped from the heap, the effort is minimal. Time is O(m n log(m n)) for the heap operations. Space is O(m n) for the distance array and heap.

04

Solution

1import heapq
2 
3class Solution:
4 def minimumEffortPath(self, heights):
5 m = len(heights)
6 n = len(heights[0])
7 dist = [[float('inf')] * n for _ in range(m)]
8 dist[0][0] = 0
9 heap = [(0, 0, 0)]
10 directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]
11 while heap:
12 effort, r, c = heapq.heappop(heap)
13 if r == m - 1 and c == n - 1:
14 return effort
15 if effort > dist[r][c]:
16 continue
17 for dr, dc in directions:
18 nr = r + dr
19 nc = c + dc
20 if 0 <= nr < m and 0 <= nc < n:
21 new_effort = max(effort, abs(heights[r][c] - heights[nr][nc]))
22 if new_effort < dist[nr][nc]:
23 dist[nr][nc] = new_effort
24 heapq.heappush(heap, (new_effort, nr, nc))
25 return 0
05

Common pitfalls

Summing edge weights instead of taking the max

✗ Wrong
new_effort = effort + abs(heights[r][c] - heights[nr][nc])
✓ Right
new_effort = max(effort, abs(heights[r][c] - heights[nr][nc]))

The problem defines effort as the maximum single step, not the total. Summing gives a different (larger) value that does not answer the question.

Not using a visited/dist check, causing infinite loops

✗ Wrong
heapq.heappush(heap, (new_effort, nr, nc))
✓ Right
if new_effort < dist[nr][nc]:
    dist[nr][nc] = new_effort
    heapq.heappush(heap, (new_effort, nr, nc))

Without the dist check, the same cell is pushed repeatedly with equal or worse efforts, bloating the heap and slowing the algorithm. In the worst case it may not terminate.

Initialising dist[0][0] to infinity instead of 0

✗ Wrong
dist = [[float('inf')] * n for _ in range(m)]
✓ Right
dist = [[float('inf')] * n for _ in range(m)]
dist[0][0] = 0

The starting cell has zero effort. Without setting it, the first pop from the heap has effort 0 but dist[0][0] = inf, and the algorithm may re-process the start or skip valid paths.

06

Edge cases

1x1 grid

Start equals destination. Effort is 0 — no edges to traverse.

All cells have the same height

Every edge has weight 0. The answer is 0 regardless of the path.

Single row or single column

Only one path exists. The answer is the maximum of consecutive differences along that path.

07

Complexity

Time
O(m * n * log(m * n))
Space
O(m * n)
Dijkstra with a binary heap. Each cell is pushed at most once with its optimal effort.