本来想用二分的,但看到题面上限制的条件:N*N的二维数组,N小于等于50,而且还限制了二维数组的值是1 ~ N * N-1
的排列,看完题解才知道能用并查集做。
题意
在时间为t的时候,水位也会上升到t,那么二维数组中本身就比t要高的平台并不会发生变化,高度小于等于t的平台变成可移动的区域,注意这里并不是在高处就能自然到低处,如[[3,2],[1,0]]这个样例,答案是3,虽然起点的平台高度是最高的,但还是要等水位上去了才能移动到其他区域。
二分查找
只说思路,t的最小解和最大解为0和N*N-1,那么可以二分答案,判断在t时刻起点能否到达终点,然后缩小范围。
并查集
感觉这种题目的限制范围就是暗示用并查集去做的,这里不能用二分了,每次二分后重新搜索图反而影响效率,所以答案t 从0开始一个一个的找,第一个成立的就是满足条件最小值了。
从t=0开始遍历,每一个时刻,就会有一个区域会变成可移动的位置,那么初始化时,只要将每个区域区分为不同的集合,然后在t时刻,高度为t的位置就可以向四周位置比它低的区域去合并,每遍历一次循环,都判断是否将起点与终点合并,是就输出,否就继续循环。
因为是0到N*N-1的排列,每个高度都是唯一的,可以定义一个数组,用高度作为下标,保存每个高度所对应的位置,那么在遍历t时,就能通过t对应的高度找到当前可以向四周扩散的坐标。
代码如下:
class Solution {
public:
int f[5]={1,0,-1,0,1};
vector<int> tu;
int find(int x){
if(tu[x]==x)return x;
tu[x] = find(tu[x]);
return tu[x];
}
void merge(int x,int y){
x = find(x),y = find(y);
tu[x]=y;
}
int swimInWater(vector<vector<int>>& grid) {
int n = grid.size();
vector<pair<int,int>> du(n*n);
for(int i = 0;i < n; ++i){
for(int j = 0;j < n; ++j){
du[grid[i][j]] = make_pair(i,j);
tu.emplace_back(i*n+j);
}
}
for(int i = 0;i < n*n; ++i){
auto [x,y] = du[i];
for(int j = 0;j < 4;j ++){
int nx = x+f[j],ny = y + f[j+1];
if(nx >=0 && nx < n && ny >= 0&& ny < n && grid[nx][ny]<=i){
merge(x*n+y,nx*n+ny);
}
}
if(find(0) == find(n*n-1))return i;
}
return -1;
}
};