class Solution {
int N;
public static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
public int swimInWater(int[][] grid) {
N = grid.length;
int[] indexs = new int[N*N];
for(int i =0;i<N;i++){
for(int j=0;j<N;j++){
indexs[grid[i][j]] = getIndex(i,j);
}
}
UnionFind uf = new UnionFind(N*N);
int t = 0;
while(uf.isConnect(getIndex(0,0),getIndex(N-1,N-1)) == false){
int index = indexs[t];
int x = index / N;
int y = index % N;
for(int[] direction:DIRECTIONS){
int newX = x + direction[0];
int newY = y + direction[1];
if(inArea(newX,newY) && grid[newX][newY] < grid[x][y])
uf.union(getIndex(newX,newY),getIndex(x,y));
}
t += 1;
}
return Math.max(0,t-1);
}
public boolean inArea(int x,int y){
return x >=0 && x < N && y >= 0 && y < N;
}
// public boolean inArea(int x,int y){
// return x>
// }
public int getIndex(int x,int y){
return x * N + y;
}
public class UnionFind{
int[] parent;
int[] rank;
public UnionFind(int n){
parent = new int[n];
rank = new int[n];
for(int i = 0;i < n;i++){
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x){
if(parent[x] != x){
parent[x] = find(parent[x]);
}
return parent[x];
}
public boolean isConnect(int x,int y){
int rootX = find(x);
int rootY = find(y);
if(rootX == rootY)
return true;
else
return false;
}
public void union(int x,int y){
int rootX = find(x);
int rootY = find(y);
if(rootX == rootY)
return ;
if(rank[rootX] == rank[rootY]){
parent[rootX] = rootY;
rank[rootY] += 1;
}
else if(rank[rootX] > rank[rootY]){
parent[rootY] = rootX;
}
else{
parent[rootX] = rootY;
}
}
}
}