文章目录
最短的桥
在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)
现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。
返回必须翻转的 0 的最小数目。(可以保证答案至少是 1 。)
示例 1:
输入:A = [[0,1],[1,0]]
输出:1
示例 2:
输入:A = [[0,1,0],[0,0,0],[0,0,1]]
输出:2
示例 3:
输入:A = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
输出:1
提示:
2 <= A.length == A[0].length <= 100
A[i][j] == 0 或 A[i][j] == 1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-bridge
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
由于有两座岛,所以需要将第一座岛找到之后,利用广度优先搜索获取第一座岛到达第二座岛的最小距离。
所以需要利用到队列这个数据结构,将距离第一座岛的大海(即原本数组的值为0的)压入队列中,然后更新它的值为3,表示大海。
对应的代码:
class Solution {
public int shortestBridge(int[][] grid) {
Queue<int[]> queue = new LinkedList<int[]>();//泛型是一个数组,用于存放第一座岛屿周围大海横坐标、纵坐标
int level = 1,size,i,j,a,b;
int[] tmp;//从队列中跳出的大海的位置
int[] move_x = new int[]{0,-1,0,1};
int[] move_y = new int[]{-1,0,1,0};
boolean isFind = false;
for(i = 0; i < grid.length; ++i){
for(j = 0; j < grid[i].length; ++j){
if(grid[i][j] == 1){
//如果值值为1,表示是岛屿,所以将和这座岛屿相邻的0压入到队列中
dfs(grid,queue,i,j);
//找到一座岛屿之后就退出循环
isFind = true;
break;
}
}
if(isFind)//找到了第一座岛屿
break;
}
while(!queue.isEmpty()){
size = queue.size();
//将第level个大海填充,然后将第level + 1个要填充的位置压入到队列中
for(i = 0; i < size; ++i){
tmp = queue.poll();
for(j = 0; j < 4; ++j){
a = tmp[0] + move_x[j];
b = tmp[1] + move_y[j];
if(a < 0 || a >= grid.length || b < 0 || b >= grid[0].length || grid[a][b] >= 2)
continue;
if(grid[a][b] == 1)
return level;
queue.offer(new int[]{a,b});
/*
标记当前这个位置访问过了,如果没有这一步,则有可能导
致超时(因为有可能将已经访问过了的大海再次添加到队列
中
*/
grid[a][b] = 3;
}
}
level++;
}
return 0;
}
/*
找到第一座岛屿,并将这一座岛屿对应的值更新为2,从而在进行广度优先搜索
的时候容易判断值为1是第二座岛
*/
public void dfs(int[][] grid,Queue<int[]> queue,int x,int y){
if(x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] >= 2)
return;//如果grid[x][y]大于等于2,表示已经访问过了,直接返回
if(grid[x][y] == 0){
queue.offer(new int[]{x,y});
grid[x][y] = 3;//标记已经被访问过了
return;
}
grid[x][y] = 2;//将第一座岛屿的值值为2,区分第二座岛屿
dfs(grid,queue,x,y - 1);
dfs(grid,queue,x - 1,y);
dfs(grid,queue,x ,y +1);
dfs(grid,queue,x + 1,y);
}
}
对应的结果:
与此题运用同样方法**(广度优先搜索)**的有:
二进制矩阵中的最短路径