934.最短的桥
题目描述
给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。
岛 是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid 中 恰好存在两座岛 。
你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛 。
返回必须翻转的 0 的最小数目。
示例图片
解题思路
方法:深度优先+广度优先结合
算法思想的主要流程是:先找到第一个岛屿的范围,并把这个岛屿范围内的值全部标记(如标记-1),这个过程可以用到深度优先方法。
确定第一个岛屿范围后,我们将第一个岛屿的边界不断向外扩张,并同样标记,一层一层扩张下去,直到扩张到第二个岛屿,那么扩张的层数即是最短桥的长度,这个不断扩张的过程刚好用到的是广度优先方法。
为了更好的理解算法,这里借用LeetCode博主 “爪哇缪斯”的算法图解过程:
代码
/** DFS寻找第一个岛屿元素 */
void DFS(int** grid,int gridSize,int i,int j,int *Queue,int *rear){
if(i<0 || i>=gridSize || j<0 || j>=gridSize || grid[i][j]!=1){
return;
}
/* 标记元素并入队 */
Queue[(*rear)++]=i*gridSize+j;
grid[i][j]=-1;
/* 上下左右分别寻找 */
DFS(grid,gridSize,i-1,j,Queue,rear);
DFS(grid,gridSize,i+1,j,Queue,rear);
DFS(grid,gridSize,i,j-1,Queue,rear);
DFS(grid,gridSize,i,j+1,Queue,rear);
return;
}
int shortestBridge(int** grid, int gridSize, int* gridColSize){
//创建队列并初始化
int *Queue=(int *)malloc(sizeof(int)*gridSize*gridSize);
int front,rear; front=rear=0;
int xy[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
int i,j,x,y,xx,yy,step;
int flag=0; //标记元素
int num; //岛屿元素个数
/* DFS寻找第一个岛 */
for(i=0;i<gridSize;i++){
for(j=0;j<gridSize;j++){
if(grid[i][j]==1){
DFS(grid,gridSize,i,j,Queue,&rear);
flag=1; break;
}
}
if(flag==1){ break; }
}
step=0;
/* BFS 第一个岛屿向外扩散 */
while(front!=rear){
num=rear-front;
for(i=1;i<=num;i++){
//队列第一个元素出队
x = Queue[front] / gridSize;
y = Queue[front] % gridSize;
front++;
for(j=0;j<4;j++){ //判断上下左右是否有0,有0扩散
xx=x+xy[j][0];
yy=y+xy[j][1];
if (xx < 0 || xx >= gridSize || yy < 0 || yy >= gridSize || grid[xx][yy] == -1) {
continue;
}
if(grid[xx][yy]==1){
return step;
}
/* 扩散元素标记入队 */
grid[xx][yy]=-1;
Queue[rear++]=gridSize*xx+yy;
}
}
step++;
}
free(Queue);
return step;
}