最短的桥
难度:
标签:
题目描述
代码结果
运行时间: 61 ms, 内存: 16.8 MB
// Java Stream Solution
// 使用Java Stream API实现的题解。我们依然首先找到第一个岛屿,然后使用BFS进行扩展,直到遇到第二个岛屿。
import java.util.*;
import java.util.stream.*;
public class Solution {
private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public int shortestBridge(int[][] grid) {
int n = grid.length;
List<int[]> island1 = new ArrayList<>();
boolean[][] visited = new boolean[n][n];
// 找到第一个岛屿并标记
outer:
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1) {
dfs(grid, i, j, island1, visited);
break outer;
}
}
}
// BFS扩展岛屿
int steps = 0;
Queue<int[]> queue = new LinkedList<>(island1);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
int[] curr = queue.poll();
for (int[] dir : DIRECTIONS) {
int x = curr[0] + dir[0];
int y = curr[1] + dir[1];
if (x >= 0 && x < n && y >= 0 && y < n && !visited[x][y]) {
if (grid[x][y] == 1) return steps;
if (grid[x][y] == 0) {
visited[x][y] = true;
queue.add(new int[]{x, y});
}
}
}
}
steps++;
}
return -1; // 理论上不会到达这里
}
private void dfs(int[][] grid, int x, int y, List<int[]> island, boolean[][] visited) {
int n = grid.length;
if (x < 0 || x >= n || y < 0 || y >= n || grid[x][y] != 1 || visited[x][y]) return;
visited[x][y] = true;
island.add(new int[]{x, y});
Arrays.stream(DIRECTIONS).forEach(dir -> dfs(grid, x + dir[0], y + dir[1], island, visited));
}
}
解释
方法:
题解的核心思路是使用广度优先搜索(BFS)来找到连接两座岛屿的最短桥。首先,通过遍历矩阵来找到第一个岛屿,并使用一个队列标记所有属于这个岛屿的坐标,同时将这些位置在grid中标记为-1以表示已访问。接着,使用多源BFS从第一个岛屿的所有位置开始扩展,搜索最短的路径到第二个岛屿。每扩展一层,步数增加1,如果遇到未访问的陆地(值为1),则返回当前步数,这表示找到了第二个岛屿,且当前步数即为需要翻转的最小0的数量。
时间复杂度:
O(n*m)
空间复杂度:
O(n*m)
代码细节讲解
🦆
如何确保在遍历矩阵时,找到的第一个岛屿是最优的起始点,或者为什么选择第一个遇到的岛屿作为起点?
▷🦆
在使用BFS搜索最短路径时,如果同时遇到多个岛屿的边缘位置,算法是如何决定优先扩展哪个位置的?
▷🦆
题解中多源BFS的`for step in range(n * m + 1)`循环中,为什么选择`n * m + 1`作为循环的上限,实际上是否可能需要这么多步骤?
▷🦆
在进行多源BFS时,每次扩展都可能会有大量的重复位置被加入队列中,这种情况下是否有更高效的方法来减少重复工作?
▷