# 778. Swim in Rising Water (Hard)

https://leetcode.com/problems/swim-in-rising-water/

On an N x N `grid`, each square `grid[i][j]` represents the elevation at that point `(i,j)`.

Now rain starts to fall. At time `t`, the depth of the water everywhere is `t`. You can swim from a square to another 4-directionally adjacent square if and only if the elevation of both squares individually are at most `t`. You can swim infinite distance in zero time. Of course, you must stay within the boundaries of the grid during your swim.

You start at the top left square `(0, 0)`. What is the least time until you can reach the bottom right square `(N-1, N-1)`?

Example 1:

```Input: [[0,2],[1,3]]
Output: 3
Explanation:
At time `0`, you are in grid location `(0, 0)`.
You cannot go anywhere else because 4-directionally adjacent neighbors have a higher elevation than t = 0.

You cannot reach point `(1, 1)` until time `3`.
When the depth of water is `3`, we can swim anywhere inside the grid.
```

Example 2:

```Input: [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
Output: 16
Explanation:
0  1  2  3  4
24 23 22 21  5
12 13 14 15 16
11 17 18 19 20
10  9  8  7  6

The final route is marked in bold.
We need to wait until time 16 so that (0, 0) and (4, 4) are connected.
```

Note:

1. `2 <= N <= 50`.
2. grid[i][j] is a permutation of [0, ..., N*N - 1].

## Solutions

``````class Solution {
public int swimInWater(int[][] grid) {
int n = grid.length;
boolean[][] visited = new boolean[n][n];
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a - b);
pq.offer(new int[]{0, 0, grid});

int[][] DIRS = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
while (!pq.isEmpty()) {
int[] curr = pq.poll();
int x = curr, y = curr, value = curr;
if (x == n - 1 && y == n - 1) {
return value;
}
// Ignore processed nodes
if (visited[x][y]) {
continue;
}
// Attention Here !!!
// record the position and distance (the position node has been pop from the priority queue)
visited[x][y] = true;

for (int[] dir : DIRS) {
int nextX = x + dir, nextY = y + dir;
if (nextX < 0 || nextX >= n || nextY < 0 || nextY >= n || visited[nextX][nextY]) {
continue;
}
pq.offer(new int[]{nextX, nextY, Math.max(value, grid[nextX][nextY])});
}
}

return -1;
}
}
``````