LeetCode/水位上升的泳池中游泳
在一个 n x n 的整数矩阵 grid 中,每一个方格的值 grid[i][j] 表示位置 (i, j) 的平台高度。
当开始下雨时,在时间为 t 时,水池中的水位为 t 。你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。
你从坐标方格的左上平台 (0,0) 出发。返回 你到达坐标方格的右下平台 (n-1, n-1) 所需的最少时间
一. 二分法+DFS
分析:时间是一个连续的量,随着时间增加最终肯定能达到目的地,这里是一个求最小的问题
初始化左边界为初始点的高度,右边界为最大高度,使用二分法加快求解
同时对二分的时间状态,判断能否连通至终点,这里使用深度优先搜索,对四个方向进行递归
边界条件为终点,同时每个时间状态要初始化一个visit二维数组记录走过的路径,用于防止折返无限递归
class Solution {
public:
vector<vector<bool>> vis;
vector<vector<int>> dir = {{0,1},{1,0},{-1,0},{0,-1}};
int swimInWater(vector<vector<int>>& grid) {
int left = grid[0][0]; int right = INT_MIN;
for(auto &x:grid)
for(int &y:x)
right = max(right,y);
int n = grid.size();
vis.resize(n,vector<bool>(n));
while(left<right){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) vis[i][j] = 0;
int mid = (left+right)/2;
//重新初始化访问记录
if(judge(0,0,mid,grid)) right = mid;//找下界
else left = mid + 1;
}
return right;
}
bool judge(int x,int y,int time,vector<vector<int>>& grid){
int n = grid.size();
if(x==n-1&&y==n-1) return true;//递归边界条件
for(int i=0;i<4;i++){//四个方向递归
int nx = x + dir[i][0]; int ny = y + dir[i][1];
if(nx>=0&&ny>=0&&nx<n&ny<n&&!vis[nx][ny]&&grid[nx][ny]<=time){//限制条件
vis[nx][ny] = true;//防止无限递归
if(judge(nx,ny,time,grid)) return true;
}
}
return false;
}
};
二. kruskal+并查集
分析:随着时间流逝,各个台子被水覆盖,可以看做是新被激活的点,通过并查集操作,将其与其他被覆盖的点进行连通
若终点最后并入初始点的集合,则此时为满足条件的最小时间
class Solution {
public:
vector<int> parent;
vector<vector<int>> dir = {{0,1},{1,0},{-1,0},{0,-1}};
int n;
int find(int i){ //寻找集合首索引,即集合的唯一标识符
if (parent[i] != i) parent[i] = find(parent[i]); //如果自己不是,递归寻找且更新索引
return parent[i];
}
void unions(int i ,int j){
parent[find(i)] = parent[find(j)];
}
bool query(int i,int j){
return find(i)==find(j);
}
int swimInWater(vector<vector<int>>& grid) {
n = grid.size();
parent.resize(n*n);
for(int i=0;i<parent.size();i++) parent[i] = i;//二维矩阵一维化
vector<vector<int>> priority(n*n,vector<int>(3));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
priority[getindex(i,j)][0]=grid[i][j];
priority[getindex(i,j)][1]=i;
priority[getindex(i,j)][2]=j;}
sort(priority.begin(),priority.end());
for(int i=0;i<priority.size();i++){//一定有解
int cur = priority[i][0];
int x = priority[i][1];
int y = priority[i][2];
for(int i=0;i<4;i++){//四个方向进行连通判断
int nx = x + dir[i][0]; int ny = y + dir[i][1];
if(nx>=0&&ny>=0&&nx<n&ny<n&&grid[nx][ny]<=cur)//限制条件
unions(getindex(x,y),getindex(nx,ny));
}
if(query(0,n*n-1)) return cur;
}
return 0;
}
int getindex(int i,int j){
return i*n+j;
}
};