Minimize maximum height along a grid path
Company: Google
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Technical Screen
You are given an `m x n` grid `heights` of **distinct** integers representing terrain heights. You start at the top-left cell `(0,0)` and want to reach the bottom-right cell `(m-1,n-1)` by moving **4-directionally** (up, down, left, right) within the grid.
Define the **cost** of a path as the **maximum height value** among all cells on that path.
### Task
Return the **minimum possible path cost**, i.e., among all valid paths from `(0,0)` to `(m-1,n-1)`, minimize the maximum height encountered.
### Input
- `heights`: `m x n` integer grid
### Output
- An integer: the minimum achievable value of `max(height on path)`
### Notes / Follow-ups discussed
- A typical approach is to model this as a shortest-path variant (e.g., Dijkstra where path “distance” is `minimize max-so-far`).
- Follow-up: Can this be implemented with DFS? If yes, what approach would you use (plain DFS vs DFS + binary search vs memoization), and what is the time complexity?
Quick Answer: This question evaluates algorithmic pathfinding and graph-modeling skills, specifically reasoning about grid-based route selection where the objective is defined by an aggregate maximum over visited cell heights.
You are given an `m x n` grid `heights` of **distinct** integers representing terrain heights. You start at the top-left cell `(0, 0)` and want to reach the bottom-right cell `(m-1, n-1)` by moving **4-directionally** (up, down, left, right) within the grid.
The **cost** of a path is the **maximum height value** among all cells on that path (including both endpoints). Among all valid paths from `(0, 0)` to `(m-1, n-1)`, return the **minimum possible path cost** — i.e., minimize the maximum height encountered.
**Example 1**
```
heights = [[1, 9],
[8, 2]]
```
The path `1 -> 8 -> 2` has cost `max(1, 8, 2) = 8`; the path `1 -> 9 -> 2` has cost `9`. Answer: `8`.
**Example 2**
```
heights = [[8, 4, 7],
[6, 5, 9],
[3, 2, 1]]
```
Every path must include the start cell `8`, so the cost is at least `8`, and `8` is achievable (e.g. `8 -> 6 -> 3 -> 2 -> 1`). Answer: `8`.
**Approach.** Model it as a shortest-path variant where a path's "distance" is the running maximum of cell heights. Run Dijkstra from `(0, 0)`: the priority queue is ordered by the smallest max-so-far, and relaxing a neighbor uses `max(current_cost, neighbor_height)`. The first time the bottom-right cell is popped, its cost is the answer.
**Follow-up (DFS).** A plain DFS that explores all paths is exponential. A practical DFS-based answer is **binary search on the answer + DFS/BFS reachability**: binary-search a threshold `T`, and check whether the bottom-right is reachable from the top-left using only cells with `height <= T` (and `start <= T`). That runs in `O(m*n*log(V))` where `V` is the number of distinct height values. DFS with memoization on `min-of-max` does not compose cleanly because the value depends on the whole path prefix, so binary search is the cleaner DFS-flavored solution.
Constraints
- 1 <= m, n
- All heights are distinct integers
- Movement is 4-directional (up, down, left, right) and must stay within the grid
- The cost of a path includes both the start cell (0,0) and the end cell (m-1,n-1)
Examples
Input: ([[1, 2, 3], [4, 5, 6], [7, 8, 9]],)
Expected Output: 9
Explanation: The bottom-right cell is 9, the grid maximum, and every path must pass through it, so the minimum achievable max is 9.
Input: ([[8, 4, 7], [6, 5, 9], [3, 2, 1]],)
Expected Output: 8
Explanation: Every path starts at 8, so the cost is at least 8; the path 8->6->3->2->1 achieves exactly 8 by avoiding the larger 9 and 7.
Input: ([[5]],)
Expected Output: 5
Explanation: Single cell: start and end coincide, so the only path cost is the value 5.
Input: ([[1, 9], [8, 2]],)
Expected Output: 8
Explanation: Path 1->8->2 has max 8, beating 1->9->2 (max 9). Answer is 8.
Input: ([[10, 20], [30, 40]],)
Expected Output: 40
Explanation: The end cell 40 is the grid maximum and is on every path, so the minimum achievable max is 40.
Input: ([[3, 1, 6, 5], [2, 8, 7, 9], [4, 12, 11, 10]],)
Expected Output: 10
Explanation: The path 3->1->6->5->9->10 along the top then down the right column avoids the large 12 and 11; its max is the end cell 10, which is optimal.
Hints
- The answer is always at least heights[0][0] and at least heights[m-1][n-1], since every path includes both endpoints.
- This is a 'minimize the maximum edge/node on a path' problem. Run Dijkstra but replace the usual sum with a running maximum: the cost to reach a neighbor is max(cost_so_far, neighbor_height).
- Pop cells from a min-heap ordered by the smallest running-max. The first time you pop the bottom-right cell, that cost is the optimal answer.
- Alternative: binary search the threshold T and test reachability with DFS/BFS using only cells whose height <= T — that is the clean 'DFS' follow-up answer in O(m*n*log V).