Path With Maximum Minimum Value
MediumUpdated: Oct 13, 2025
Practice on:
Problem
Given an m x n integer matrix grid, return _the maximumscore of a path starting at _(0, 0)and ending at(m - 1, n - 1) moving in the 4 cardinal directions.
The score of a path is the minimum value in that path.
- For example, the score of the path
8 -> 4 -> 5 -> 9is4.
Examples
Example 1:
\Huge
\begin{array}{|c|c|c|c|}
\hline
\colorbox{YellowOrange} 5 & \colorbox{YellowOrange} 4 & \colorbox{YellowOrange} 5 \\\
\hline
1 & 2 & \colorbox{YellowOrange} 6 \\\
\hline
7 & 4 & \colorbox{YellowOrange} 6 \\\
\hline
\end{array}
Input: grid = [[5,4,5],[1,2,6],[7,4,6]]
Output: 4
Explanation: The path with the maximum score is highlighted in yellow.
Example 2:
\Huge
\begin{array}{|c|c|c|c|c|c|}
\hline
\colorbox{YellowOrange}2 & \colorbox{YellowOrange}2 & 1 & \colorbox{YellowOrange}2 & \colorbox{YellowOrange}2 & \colorbox{YellowOrange}2 \\\
\hline
1 & \colorbox{YellowOrange}2 & \colorbox{YellowOrange}2 & \colorbox{YellowOrange}2 & 1 & \colorbox{YellowOrange}2 \\\
\hline
\end{array}
Input: grid = [[2,2,1,2,2,2],[1,2,2,2,1,2]]
Output: 2
Explanation: one valid maximum-minimum path (minimum value = 2) is highlighted above — for example, the route (0,0)→(0,1)→(1,1)→(1,2)→(1,3)→(0,3)→(0,4)→(0,5)→(1,5) (0-based indices: (row,col)).
Example 3:
\Huge
\begin{array}{|c|c|c|c|c|}
\hline
\colorbox{YellowOrange}3 & \colorbox{YellowOrange}4 & \colorbox{YellowOrange}6 & \colorbox{YellowOrange}3 & \colorbox{YellowOrange}4 \\\
\hline
0 & 2 & 1 & 1 & \colorbox{YellowOrange}7 \\\
\hline
\colorbox{YellowOrange}8 & \colorbox{YellowOrange}8 & \colorbox{YellowOrange}3 & 2 & \colorbox{YellowOrange}7 \\\
\hline
\colorbox{YellowOrange}3 & 2 & \colorbox{YellowOrange}4 & \colorbox{YellowOrange}9 & \colorbox{YellowOrange}8 \\\
\hline
\colorbox{YellowOrange}4 & 1 & 2 & 0 & 0 \\\
\hline
\colorbox{YellowOrange}4 & \colorbox{YellowOrange}6 & \colorbox{YellowOrange}5 & \colorbox{YellowOrange}4 & \colorbox{YellowOrange}3 \\\
\hline
\end{array}
Input: grid = [[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]]
Output: 3
Explanation: the highlighted cells show one valid path whose minimum value is 3 (for example: (0,0)→(0,1)→(0,2)→(0,3)→(0,4)→(1,4)→(2,4)→(3,4)→(3,3)→(3,2)→(2,2)→(2,1)→(2,0)→(3,0)→(4,0)→(5,0)→(5,1)→(5,2)→(5,3)→(5,4)).
Constraints:
m == grid.lengthn == grid[i].length1 <= m, n <= 1000 <= grid[i][j] <= 10^9
Solution
Method 1 - Max-Heap Greedy BFS (Priority Queue)
Intuition
We want the path from (0,0) to (m-1,n-1) whose minimum value along the path is maximized. This is a classic "maximum minimum path" problem, which can be solved using a max-heap (priority queue) with BFS/DFS, or binary search + BFS/DFS/Union-Find.
Approach
Use a max-heap to always expand the path with the highest minimum value so far. For each cell, keep track of the best minimum value to reach it. Stop when we reach the bottom-right cell.
Code
C++
#include <vector>
#include <queue>
using namespace std;
class Solution {
public:
int maximumMinimumPath(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
vector<vector<int>> vis(m, vector<int>(n, 0));
priority_queue<tuple<int,int,int>> pq;
pq.emplace(grid[0][0], 0, 0);
int dirs[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
while (!pq.empty()) {
auto [val, x, y] = pq.top(); pq.pop();
if (x == m-1 && y == n-1) return val;
if (vis[x][y]) continue;
vis[x][y] = 1;
for (auto& d : dirs) {
int nx = x + d[0], ny = y + d[1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && !vis[nx][ny])
pq.emplace(min(val, grid[nx][ny]), nx, ny);
}
}
return -1;
}
};
Go
import "container/heap"
type Item struct{ val, x, y int }
type PQ []Item
func (h PQ) Len() int { return len(h) }
func (h PQ) Less(i, j int) bool { return h[i].val > h[j].val }
func (h PQ) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *PQ) Push(x any) { *h = append(*h, x.(Item)) }
func (h *PQ) Pop() any { old := *h; x := old[len(old)-1]; *h = old[:len(old)-1]; return x }
func maximumMinimumPath(grid [][]int) int {
m, n := len(grid), len(grid[0])
vis := make([][]bool, m)
for i := range vis { vis[i] = make([]bool, n) }
pq := &PQ{{grid[0][0], 0, 0}}
heap.Init(pq)
dirs := [][2]int{{0,1},{1,0},{0,-1},{-1,0}}
for pq.Len() > 0 {
item := heap.Pop(pq).(Item)
val, x, y := item.val, item.x, item.y
if x == m-1 && y == n-1 { return val }
if vis[x][y] { continue }
vis[x][y] = true
for _, d := range dirs {
nx, ny := x+d[0], y+d[1]
if nx >= 0 && nx < m && ny >= 0 && ny < n && !vis[nx][ny] {
heap.Push(pq, Item{min(val, grid[nx][ny]), nx, ny})
}
}
}
return -1
}
func min(a, b int) int { if a < b { return a } else { return b } }
Java
import java.util.*;
class Solution {
public int maximumMinimumPath(int[][] grid) {
int m = grid.length, n = grid[0].length;
boolean[][] vis = new boolean[m][n];
PriorityQueue<int[]> pq = new PriorityQueue<>((a,b)->b[0]-a[0]);
pq.offer(new int[]{grid[0][0], 0, 0});
int[][] dirs = {{0,1},{1,0},{0,-1},{-1,0}};
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int val = cur[0], x = cur[1], y = cur[2];
if (x == m-1 && y == n-1) return val;
if (vis[x][y]) continue;
vis[x][y] = true;
for (int[] d : dirs) {
int nx = x + d[0], ny = y + d[1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && !vis[nx][ny])
pq.offer(new int[]{Math.min(val, grid[nx][ny]), nx, ny});
}
}
return -1;
}
}
Kotlin
class Solution {
fun maximumMinimumPath(grid: Array<IntArray>): Int {
val m = grid.size; val n = grid[0].size
val vis = Array(m) { BooleanArray(n) }
val pq = java.util.PriorityQueue(compareByDescending<Triple<Int,Int,Int>> { it.first })
pq.add(Triple(grid[0][0], 0, 0))
val dirs = arrayOf(0 to 1, 1 to 0, 0 to -1, -1 to 0)
while (pq.isNotEmpty()) {
val (val_, x, y) = pq.poll()
if (x == m-1 && y == n-1) return val_
if (vis[x][y]) continue
vis[x][y] = true
for ((dx, dy) in dirs) {
val nx = x + dx; val ny = y + dy
if (nx in 0 until m && ny in 0 until n && !vis[nx][ny])
pq.add(Triple(minOf(val_, grid[nx][ny]), nx, ny))
}
}
return -1
}
}
Python
import heapq
from typing import List
class Solution:
def maximumMinimumPath(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
vis = [[False]*n for _ in range(m)]
pq = [(-grid[0][0], 0, 0)]
while pq:
val, x, y = heapq.heappop(pq)
val = -val
if x == m-1 and y == n-1:
return val
if vis[x][y]: continue
vis[x][y] = True
for dx, dy in ((0,1),(1,0),(0,-1),(-1,0)):
nx, ny = x+dx, y+dy
if 0 <= nx < m and 0 <= ny < n and not vis[nx][ny]:
heapq.heappush(pq, (-min(val, grid[nx][ny]), nx, ny))
return -1
Rust
use std::collections::BinaryHeap;
fn maximumMinimumPath(grid: Vec<Vec<i32>>) -> i32 {
let (m, n) = (grid.len(), grid[0].len());
let mut vis = vec![vec![false; n]; m];
let mut pq = BinaryHeap::new();
pq.push((grid[0][0], 0usize, 0usize));
let dirs = [(0isize,1isize),(1,0),(0,-1),(-1,0)];
while let Some((val, x, y)) = pq.pop() {
if x == m-1 && y == n-1 { return val; }
if vis[x][y] { continue; }
vis[x][y] = true;
for (dx, dy) in dirs.iter() {
let nx = x as isize + dx; let ny = y as isize + dy;
if nx >= 0 && nx < m as isize && ny >= 0 && ny < n as isize && !vis[nx as usize][ny as usize] {
pq.push((val.min(grid[nx as usize][ny as usize]), nx as usize, ny as usize));
}
}
}
-1
}
TypeScript
function maximumMinimumPath(grid: number[][]): number {
const m = grid.length, n = grid[0].length;
const vis = Array.from({length: m}, () => Array(n).fill(false));
const pq: [number, number, number][] = [[grid[0][0], 0, 0]];
pq.sort((a, b) => b[0] - a[0]);
const dirs = [[0,1],[1,0],[0,-1],[-1,0]];
while (pq.length) {
const [val, x, y] = pq.shift()!;
if (x === m-1 && y === n-1) return val;
if (vis[x][y]) continue;
vis[x][y] = true;
for (const [dx, dy] of dirs) {
const nx = x+dx, ny = y+dy;
if (nx >= 0 && nx < m && ny >= 0 && ny < n && !vis[nx][ny])
pq.push([Math.min(val, grid[nx][ny]), nx, ny]);
}
pq.sort((a, b) => b[0] - a[0]);
}
return -1;
}
Complexity
- ⏰ Time complexity:
O(mn log(mn)) - 🧺 Space complexity:
O(mn)