2.Shortest Bridge
题目描述
给定一个二维 0-1 矩阵,其中 1 表示陆地,0 表示海洋,每个位置与上下左右相连。已知矩阵中有且只有两个岛屿,求最少要填海造陆多少个位置才可以将两个岛屿相连。
输入是一个二维整数数组,输出是一个非负整数,表示需要填海造陆的位置数。
Input:
[[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]]
Output: 1
思路:
- 找到其中一个岛屿,用深度优先算法将其区分出来(即将1变为2)。
- 用广度优先搜索,找寻到达另一个岛屿的最短路径。
import java.util.LinkedList;
import java.util.Queue;
public class ShortBri {
public static int[] directions = {
-1,0,1,0,-1};//相邻两数代表一个方向
public static int shortestBirge(int[][] gird){
int row = gird.length;//行数
int col = gird[0].length;//列数
Queue<Point> points = new LinkedList<>();
boolean flag = false;
for (int i = 0; i < row; i++) {
if (flag) break;
for (int j = 0; j < col; j++) {
//1.找到第一个岛屿用深度优先遍历将所有为1的点变成2
if (gird[i][j] == 1){
dfs(points,gird,i,j,row,col);
flag = true;
break;
}
}
}
//2.用广度优先搜索获取到达第二个岛屿的最短路径
int x,y;
int step = 0;
while (!points.isEmpty()){
++step;
int n = points.size();
while ((n--) != 0){
//将之前进入队列的全部遍历一遍
Point point = points.poll();
x = point.x;
y = point.y;
for (int i = 0; i < 4; i++) {
x = x + directions[i];
y = y + directions[i+1];
if (x >= 0 && y >= 0 && x < row && y <col ){
//在边界条件内搜寻
if (gird[x][y] == 2){
//是搜寻过的地方
continue;
}
if (gird[x][y] == 1){
//找到另一个岛屿
return step;
}
gird[x][y] = 2;
points.offer(new Point(x,y));
}
}
}
}
return 0;
}
//深度优先搜索
public static void dfs(Queue<Point> points,int[][] gird,int i,int j,int row,int col){
if ((i < 0)||(j < 0)||(i == row)||(j == col)||(gird[i][j] == 2)){
return;
}
if (gird[i][j] == 0){
points.offer(new Point(i,j));//入队
return;
}
gird[i][j] = 2;
//沿左、上、右、下进行搜索
dfs(points,gird,i-1,j,row,col);
dfs(points,gird,i+1,j,row,col);
dfs(points,gird,i,j-1,row,col);
dfs(points,gird,i,j+1,row,col);
}
//测试
public static void main(String[] args) {
int[][] gird ={
{
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}};
System.out.println(shortestBirge(gird));
for (int[] ints : gird) {
for (int anInt : ints) {
System.out.print(anInt+" ");
}
System.out.println();
}
}
}
class Point{
//记录二维数组中元素的下标。
int x;
int y;
public Point(int x,int y){
this.x = x;
this.y = y;
}
}