## 778. 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].

## Rust Solution

``````struct Solution;

use std::cmp::Reverse;
use std::collections::BinaryHeap;

struct UnionFind {
parent: Vec<usize>,
n: usize,
}

impl UnionFind {
fn new(n: usize) -> Self {
let parent = (0..n).collect();
UnionFind { parent, n }
}

fn find(&mut self, i: usize) -> usize {
let j = self.parent[i];
if i == j {
i
} else {
let k = self.find(j);
self.parent[i] = k;
k
}
}

fn union(&mut self, i: usize, j: usize) {
let i = self.find(i);
let j = self.find(j);
if i != j {
self.parent[i] = j;
}
}
}

impl Solution {
fn swim_in_water(grid: Vec<Vec<i32>>) -> i32 {
let n = grid.len();
let mut uf = UnionFind::new(n * n);
let mut queue: BinaryHeap<(Reverse<i32>, usize, usize)> = BinaryHeap::new();
for i in 0..n {
for j in 0..n {
queue.push((Reverse(grid[i][j]), i, j));
}
}
while let Some((Reverse(t), r, c)) = queue.pop() {
let i = r * n + c;
if grid[r][c] <= t && r > 0 && grid[r - 1][c] <= t {
let j = (r - 1) * n + c;
uf.union(i, j);
}
if grid[r][c] <= t && r + 1 < n && grid[r + 1][c] <= t {
let j = (r + 1) * n + c;
uf.union(i, j);
}
if grid[r][c] <= t && c > 0 && grid[r][c - 1] <= t {
let j = r * n + (c - 1);
uf.union(i, j);
}
if grid[r][c] <= t && c + 1 < n && grid[r][c + 1] <= t {
let j = r * n + (c + 1);
uf.union(i, j);
}
if uf.find(0) == uf.find(n * n - 1) {
return t;
}
}
0
}
}

#[test]
fn test() {
let grid = vec_vec_i32![[0, 2], [1, 3]];
let res = 3;
assert_eq!(Solution::swim_in_water(grid), res);
let grid = vec_vec_i32![
[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]
];
let res = 16;
assert_eq!(Solution::swim_in_water(grid), res);
}
``````

Having problems with this solution? Click here to submit an issue on github.