在一个 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) 是连通的
一开始位于(0,0)节点,判断周围的节点能否合并,如果可以,则合并;如果不行则持续增加 t 的值,循环直到可以合并最后一个格子。
class Solution778{
List<coordinate> nodes = new ArrayList();
int column;
public int swimInWater(int[][] grid) {
if (grid == null || grid.length == 0)
return 0;
int row = grid.length;
this.column = grid[0].length;
UnionUF778 uf = new UnionUF778(row * column);
//一开始位于(0,0)平台
nodes.add(new coordinate(0, 0));
int t = grid[0][0];
while (true) {
for (int i = 0; i < nodes.size(); i++) {
coordinate node = nodes.get(i);
int x = node.x;
int y = node.y;
//如果当前平台和上平台不在同一个集合 则判断上平台可否联合
if (x > 0 && !uf.isConnected(node(x, y), node(x - 1, y))) {
if (t >= grid[x - 1][y]) {
uf.union(node(x, y), node(x - 1, y));
nodes.add(new coordinate(x - 1, y));
}
}
//如果当前平台和下平台不在同一个集合
if (x + 1 < row && !uf.isConnected(node(x, y), node(x+1, y ))) {
if (t >= grid[x + 1][y]) {
//则判断下平台可否联合
uf.union(node(x, y), node(x + 1, y));
nodes.add(new coordinate(x + 1, y));
}
}
//左
if (y > 0 && !uf.isConnected(node(x, y), node(x, y - 1))) {
if (t >= grid[x][y - 1]) {
uf.union(node(x, y), node(x, y - 1));
nodes.add(new coordinate(x, y - 1));
}
}
//右
if (y + 1 < column && !uf.isConnected(node(x, y), node(x, y + 1))) {
if (t >= grid[x][y + 1]) {
uf.union(node(x, y), node(x, y + 1));
nodes.add(new coordinate(x, y + 1));
}
}
}
if (uf.isConnected(node(0, 0), node(row - 1, column - 1)))
return t;
t++;
}
}
//将二维坐标转换为一维坐标
public int node(int i,int j){
return i*column+j;
}
}
class coordinate{
int x;
int y;
public coordinate(int x,int y){
this.x = x;
this.y = y;
}
}
class UnionUF778{
/**
* 对象索引数组 id[i]表示第i个节点的父节点为id[i]
*/
int[] id;
int[] size;
public UnionUF778(int N){
id = new int[N];
size = new int[N];
for(int i=0;i<N;i++){
id[i] = i;
size[i] = 1;
}
}
public void union(int x,int y){
int Rx = find(x);
int Ry = find(y);
if(Rx == Ry)
return;
if(size[Rx] >= size[Ry]){
id[Ry] = Rx;
size[Rx] += size[Ry];
}else{
id[Rx] = Ry;
size[Ry] += size[Rx];
}
}
public int find(int p){
while(p != id[p]){
id[p] = id[id[p]];
p = id[p];
}
return p;
}
public boolean isConnected(int p,int q){
return find(p) == find(q);
}
}
遍历 grid 数组,找到最高水位,每次取最高水位的一半val,判断用 val 能否走到最后一个格子:
1)如果可以,说明当前 val 可能是答案(因为答案有可能比当前 val 还要小),此时缩小val的范围
2)如果不行,说明当前 val 太小需要变大。
static int row;
static int column;
int[][] grid;
//是否到达最后一个格子
boolean isarrvie = false;
public int swimInWater3(int[][] grid){
if(grid==null || grid.length==0)
return 0;
this.row = grid.length;
this.column = grid[0].length;
this.grid = grid;
boolean[][] visited = new boolean[row][column];
int right = 0,left=grid[0][0],minTime = Integer.MAX_VALUE;
for(int i=0;i<row;i++)
for(int j=0;j<column;j++)
right = Math.max(right,grid[i][j]);
//用二分查找最小耗时
while(left <= right){
int mid = (left + right) / 2;
//如果当前val可以到达最后一个格子
//则缩小范围继续查找有没有更小的val
if(check(visited,mid)){
right = mid - 1;
minTime = mid;
}else{
//不行则表示当前val太小
left = mid + 1;
}
}
return minTime;
}
//判断val能否到达最后一个格子
public boolean check(boolean[][] visit,int val){
isarrvie = false;
//保证每次传进来的visit都是全新数组
for(int i=0;i<row;i++)
for(int j=0;j<column;j++)
visit[i][j] = false;
visit[0][0] = true;
dfs(0,0,val,visit);
return isarrvie;
}
//从[i][j]格子,以val的值出发 能否到达最后一个格子
public void dfs(int i,int j,int val,boolean[][] visit){
//已到达最后一个格子
if(i==row-1 && j==column-1)
isarrvie = true;
if(isarrvie)
return;
visit[i][j] = true;
//判断能否到达下一个格子
if(i+1<row && !visit[i+1][j] && val>=grid[i+1][j])
dfs(i+1,j,val,visit);
//右
if(j+1<column && !visit[i][j+1] && val>=grid[i][j+1])
dfs(i,j+1,val,visit);
//上
if(i>0 && !visit[i-1][j] && val>=grid[i-1][j])
dfs(i-1,j,val,visit);
//左
if(j>0 && !visit[i][j-1] && val>=grid[i][j-1])
dfs(i,j-1,val,visit);
}