Swim in Rising Water
Problem
You are given a square 2-D matrix of distinct integers grid where each integer grid[i][j] represents the elevation at position (i, j).
Rain starts to fall at time = 0, which causes the water level to rise. At time t, the water level across the entire grid is t.
You may swim either horizontally or vertically in the grid between two adjacent squares if the original elevation of both squares is less than or equal to the water level at time t.
Starting from the top left square (0, 0), return the minimum amount of time it will take until it is possible to reach the bottom right square (n - 1, n - 1).
Examples
Example 1:

Input: grid = [[0,1],[2,3]]
Output: 3
Explanation: For a path to exist to the bottom right square grid[1][1] the water elevation must be at least 3. At time t = 3, the water level is 3.
Example 2:

Input: grid = [
[0,1,2,10],
[9,14,4,13],
[12,3,8,15],
[11,5,7,6]
]
Output: 8
Explanation: The water level must be at least 8 to reach the bottom right square. The path is [0, 1, 2, 4, 8, 7, 6].
Constraints
grid.length == grid[i].length1 <= grid.length <= 500 <= grid[i][j] < n^2
You should aim for a solution with O((n^2)logn) time and O(n^2) space, where n is the number of rows or columns of the square matrix.
Solution
We run BFS, where we are optimizing for the time. We can move between cells with 0 cost, so long as the heights are less than or equal to the time.
class Solution {
inline static constexpr std::array<std::pair<int, int>, 5> OFFSETS = {{
{-1, 0}, {1, 0}, {0, -1}, {0, 1}
}};
struct Node {
int r;
int c;
int t;
};
public:
int swimInWater(vector<vector<int>>& grid) {
const int ROWS = grid.size();
const int COLS = grid[0].size();
auto cmp = [](const Node& a, const Node& b) {
return a.t > b.t; // min-heap by time
};
std::priority_queue<Node, std::vector<Node>, decltype(cmp)> open(cmp);
std::unordered_set<int> closed;
open.emplace(0, 0, grid[0][0]);
while (!open.empty()) {
auto current = open.top();
open.pop();
// Previously visited
if (closed.contains(current.r * COLS + current.c)) {
continue;
}
closed.insert(current.r * COLS + current.c);
// Solution
if (current.r == ROWS - 1 && current.c == COLS - 1) {
return current.t;
}
for (const auto &[dr, dc] : OFFSETS) {
int rr = current.r + dr;
int cc = current.c + dc;
// Out of bounds
if (rr < 0 || cc < 0 || rr >= ROWS || cc >= COLS) { continue; }
int next_time = std::max(current.t, grid[rr][cc]);
open.emplace(rr, cc, next_time);
}
}
return -1;
}
};