题目链接
https://leetcode.cn/problems/shortest-bridge/
题目来源于: 第109场周赛 Q3 rating: 1825
思路一(两次dfs)
题目要求的实际上是两个由1组成的连通块之间的最小距离。
那么直接可以想到:把这两个连通块内的所有点分别求出来,然后O(n2)遍历这些点,求它们的最小距离即为答案。
两次dfs(深度优先搜索)即可得到两个连通块内的所有点。
代码一
class Solution {
vector<pair<int,int> > g[2]; // 分别存2个连通块内的所有点的坐标
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[110][110];
// 以(x,y)为起点,开始找值为1的连通块
void dfs(int x,int y,vector<vector<int>>& grid,vector<pair<int,int> >& ans){
int n=grid.size();
vis[x][y]=1;
ans.push_back(make_pair(x,y));
for(int i=0;i<4;i++){
int new_x=x+dir[i][0];
int new_y=y+dir[i][1];
if(new_x>=0&&new_x<n&&new_y>=0&&new_y<n&&grid[new_x][new_y]&&!vis[new_x][new_y]){
dfs(new_x,new_y,grid,ans);
}
}
}
public:
int shortestBridge(vector<vector<int>>& grid) {
memset(vis,0,sizeof(vis));
int n=grid.size();
int cnt=0; // 连通块的编号,cnt=0或1
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(grid[i][j]&&!vis[i][j]){
// 题目条件“两个连通块”限制只会搜索两次
dfs(i,j,grid,g[cnt]);
cnt++;
}
}
}
int mi=0x3f3f3f3f;
for(int i=0;i<g[0].size();i++){
for(int j=0;j<g[1].size();j++){
auto [x1,y1]=g[0][i];
auto [x2,y2]=g[1][j];
int dis=abs(x1-x2)+abs(y1-y2)-1;
assert(dis>0);
mi=min(mi,dis);
}
}
return mi;
}
};
思路二(一次dfs + 一次bfs)
一次dfs把第一个连通块内的所有点(值为1)加入到队列中,然后开始一次bfs(广度优先搜索),每次扩展一层值为0的点,直到扩展到值为1的点,说明遇到了第二个连通块,结束bfs。bfs扩展的步数即为答案。
代码二
class Solution {
struct node{
int x,y,cnt;
};
queue<node> q; // 用于bfs的队列
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[110][110];
// 以(x,y)为起点,开始找值为1的连通块
void dfs(int x,int y,vector<vector<int>>& grid){
int n=grid.size();
vis[x][y]=1;
q.push({x,y,0}); // 第一个连通块的所有点加入队列,初始步数为0
for(int i=0;i<4;i++){
int new_x=x+dir[i][0];
int new_y=y+dir[i][1];
if(new_x>=0&&new_x<n&&new_y>=0&&new_y<n&&grid[new_x][new_y]&&!vis[new_x][new_y]){
dfs(new_x,new_y,grid);
}
}
}
public:
int shortestBridge(vector<vector<int>>& grid) {
memset(vis,0,sizeof(vis));
int n=grid.size();
bool flag=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(grid[i][j]){
// 由flag限制只找一个连通块
dfs(i,j,grid);
flag=1; // 找到一个连通块了
break; // 结束第二层循环
}
}
if(flag){
break; // 结束第一层循环
}
}
while(!q.empty()){
auto [x,y,cnt]=q.front();
q.pop();
for(int i=0;i<4;i++){
int new_x=x+dir[i][0];
int new_y=y+dir[i][1];
if(new_x>=0&&new_x<n&&new_y>=0&&new_y<n&&!vis[new_x][new_y]){
vis[new_x][new_y]=1;
if(!grid[new_x][new_y]){
q.push({new_x,new_y,cnt+1});
}else if(grid[new_x][new_y]){
return cnt;
}
}
}
}
return -1;
}
};