一、题目描述
在一个 N x N 的坐标方格 grid 中,每一个方格的值 grid[i][j] 表示在位置 (i,j) 的平台高度。
现在开始下雨了。当时间为 t 时,此时雨水导致水池中任意位置的水位为 t 。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。当然,在你游泳的时候你必须待在坐标方格里面。
你从坐标方格的左上平台 (0,0) 出发。最少耗时多久你才能到达坐标方格的右下平台 (N-1, N-1)?
示例 1:
输入: [[0,2],[1,3]]
输出: 3
解释:
时间为0时,你位于坐标方格的位置为 (0, 0)。
此时你不能游向任意方向,因为四个相邻方向平台的高度都大于当前时间为 0 时的水位。
等时间到达 3 时,你才可以游向平台 (1, 1). 因为此时的水位是 3,坐标方格中的平台没有比水位 3 更高的,所以你可以游向坐标方格中的任意位置
示例2:
输入: [[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]]
输出: 16
解释:
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
最终的路线用加粗进行了标记。
我们必须等到时间为 16,此时才能保证平台 (0, 0) 和 (4, 4) 是连通的
难度:困难
二、题解
class UnionFind{
public:
int n;
int count;
vector<int> parent;
vector<int> size;
public:
UnionFind(int _n):n(_n),count(_n),size(_n,1),parent(_n){
iota(parent.begin(), parent.end(), 0);
}
int find(int x){
return parent[x] == x ? x : parent[x] = find(parent[x]);
}
bool merge(int x,int y){
x = find(x);
y = find(y);
if(x == y)
return true;
if(size[x]<=size[y])
parent[x] = y;
else
parent[y] = x;
if(size[x]==size[y])
size[y]++;
--count;
return false;
}
bool isConnect(int x,int y){
x = find(x);
y = find(y);
return x == y;
}
};
class Solution {
private:
int N;
int DIRECTIONS[4][2] = {
{
0, 1}, {
0, -1}, {
1, 0}, {
-1, 0}};
public:
int swimInWater(vector<vector<int>>& grid) {
N = grid.size();
int len = N * N;
UnionFind uf(len);
vector<int> index(len);
for(int i=0;i<N;i++){
for(int j =0;j<N;j++){
index[grid[i][j]] = getIndex(i,j);//下标为平台高度,值为结点值
}
}
for(int t=0;t<len;t++){
//t为时间
//时间t对应的结点位置
int x = index[t] / N;
int y = index[t] % N;
//上下左右四个方向
for(int k=0;k<4;k++){
int newX = x + DIRECTIONS[k][0];
int newY = y + DIRECTIONS[k][1];
//r如果有小于等于当前时刻的坐标,则合并
if(inArea(newX,newY)&&grid[newX][newY]<=t)
uf.merge(index[t],getIndex(newX,newY));
if(uf.isConnect(0,len-1))
return t;
}
}
return -1;
}
int getIndex(int x,int y){
return x * N + y;
}
bool inArea(int x,int y){
return x>=0&&x<N&&y>=0&&y<N;
}
};