Imagine you're a treasure hunter navigating through a dangerous dungeon represented by an m × n grid. Each cell contains a number representing the safety level of that location. You must find a path from the top-left corner (0, 0) to the bottom-right corner (m-1, n-1), moving only up, down, left, or right.
Here's the catch: your journey is only as safe as its weakest point. The score of any path is the minimum value encountered along that route. Your goal is to find the path that maximizes this minimum value.
Example: If you traverse cells with values 8 → 4 → 5 → 9, your path score is 4 (the minimum). You want to find the path where this minimum is as large as possible!
Input & Output
example_1.py — Basic 3x3 Grid
$Input:grid = [[5,4,5],[1,2,6],[7,4,6]]
›Output:4
💡 Note:The optimal path is 5 → 4 → 6 → 6 with minimum value 4. Alternative paths like 5 → 1 → 2 → 6 → 6 have minimum value 1, which is worse.
example_2.py — Simple 2x3 Grid
$Input:grid = [[2,2,1],[2,2,2]]
›Output:2
💡 Note:The path 2 → 2 → 2 → 2 gives minimum value 2. We cannot do better since we must end at the bottom-right corner.
💡 Note:The optimal path maintains a minimum value of 3 by carefully navigating through higher-value cells and avoiding the zeros at the bottom-right area.
Constraints
m == grid.length
n == grid[i].length
1 ≤ m, n ≤ 100
0 ≤ grid[i][j] ≤ 109
You can move in 4 directions: up, down, left, right
Visualization
Tap to expand
Understanding the Visualization
1
Understanding the Problem
Each path's score is its weakest link - we want to maximize this minimum value
2
Why Dijkstra Works
Instead of finding shortest path, we find the path that maximizes the bottleneck value
3
Priority Queue Strategy
Always explore the most promising path first - the one with highest minimum so far
4
Optimal Solution Found
First time we reach destination gives us the optimal maximum minimum value
Key Takeaway
🎯 Key Insight: This is a bottleneck shortest path problem - use Dijkstra's algorithm with max-heap to find the path that maximizes the minimum value encountered!
The optimal solution uses Dijkstra's algorithm with a max-heap to always explore paths with the highest minimum value first. This approach guarantees finding the path that maximizes the minimum value in O(mn log(mn)) time, making it efficient for the given constraints.
Common Approaches
Approach
Time
Space
Notes
✓
Dijkstra's Algorithm (Optimal)
O(mn log(mn))
O(mn)
Modified Dijkstra's algorithm to maximize the minimum value along the path
DFS with All Paths (Brute Force)
O(4^(m*n))
O(m*n)
Explore all possible paths using DFS and track the maximum minimum value
Binary Search + BFS/DFS
O(mn * log(max-min))
O(mn)
Binary search on the answer, then verify if path exists with BFS/DFS
Dijkstra's Algorithm (Optimal) — Algorithm Steps
Initialize max-heap with starting cell and its value
Pop cell with maximum minimum value so far
If we reach destination, return the minimum value
Add unvisited neighbors to heap with updated minimum
Continue until destination is reached
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Initialize heap
Start with source cell in max-heap
2
Pop best candidate
Always process cell with highest minimum value
3
Explore neighbors
Add neighbors with updated minimum values
4
Reach destination
First time we reach destination gives optimal answer
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct {
int minVal, row, col;
} HeapItem;
typedef struct {
HeapItem* data;
int size, capacity;
} MaxHeap;
MaxHeap* createHeap(int capacity) {
MaxHeap* heap = (MaxHeap*)malloc(sizeof(MaxHeap));
heap->data = (HeapItem*)malloc(capacity * sizeof(HeapItem));
heap->size = 0;
heap->capacity = capacity;
return heap;
}
void heapifyUp(MaxHeap* heap, int idx) {
while (idx > 0) {
int parent = (idx - 1) / 2;
if (heap->data[parent].minVal >= heap->data[idx].minVal) break;
HeapItem temp = heap->data[parent];
heap->data[parent] = heap->data[idx];
heap->data[idx] = temp;
idx = parent;
}
}
void heapifyDown(MaxHeap* heap, int idx) {
while (true) {
int largest = idx;
int left = 2 * idx + 1;
int right = 2 * idx + 2;
if (left < heap->size && heap->data[left].minVal > heap->data[largest].minVal) {
largest = left;
}
if (right < heap->size && heap->data[right].minVal > heap->data[largest].minVal) {
largest = right;
}
if (largest == idx) break;
HeapItem temp = heap->data[idx];
heap->data[idx] = heap->data[largest];
heap->data[largest] = temp;
idx = largest;
}
}
void push(MaxHeap* heap, HeapItem item) {
heap->data[heap->size] = item;
heapifyUp(heap, heap->size);
heap->size++;
}
HeapItem pop(MaxHeap* heap) {
HeapItem result = heap->data[0];
heap->data[0] = heap->data[heap->size - 1];
heap->size--;
heapifyDown(heap, 0);
return result;
}
int maximumMinimumPath(int** grid, int m, int n) {
int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
MaxHeap* heap = createHeap(m * n * 4);
HeapItem start = {grid[0][0], 0, 0};
push(heap, start);
bool** visited = (bool**)malloc(m * sizeof(bool*));
for (int i = 0; i < m; i++) {
visited[i] = (bool*)calloc(n, sizeof(bool));
}
int result = -1;
while (heap->size > 0) {
HeapItem curr = pop(heap);
int minVal = curr.minVal, row = curr.row, col = curr.col;
if (visited[row][col]) continue;
visited[row][col] = true;
if (row == m - 1 && col == n - 1) {
result = minVal;
break;
}
for (int i = 0; i < 4; i++) {
int nr = row + directions[i][0];
int nc = col + directions[i][1];
if (nr >= 0 && nr < m && nc >= 0 && nc < n && !visited[nr][nc]) {
int newMin = (grid[nr][nc] < minVal) ? grid[nr][nc] : minVal;
HeapItem next = {newMin, nr, nc};
push(heap, next);
}
}
}
for (int i = 0; i < m; i++) {
free(visited[i]);
}
free(visited);
free(heap->data);
free(heap);
return result;
}
int main() {
// Parse input and call solution
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(mn log(mn))
Each cell is processed once, and heap operations take log(mn) time
n
2n
⚡ Linearithmic
Space Complexity
O(mn)
Priority queue can hold up to mn elements, plus visited array
n
2n
⚡ Linearithmic Space
28.5K Views
MediumFrequency
~25 minAvg. Time
892 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.