934. 最短的桥
描述
在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)
现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。
返回必须翻转的 0 的最小数目。(可以保证答案至少是 1 。)
题解
广度优先搜索(breadth-first search,BFS)不同与深度优先搜索,它是一层层进行遍历的,因 此需要用先入先出的队列而非先入后出的栈进行遍历。由于是按层次进行遍历,广度优先搜索时 按照“广”的方向进行遍历的,也常常用来处理最短路径等问题。
目前这道题很明显这是在求两个岛屿间的最短距离。 步骤: 1、任意搜索方法找到其中一个岛 2、利用广度优先搜索,查找其与另一个岛屿的最短距离,用先入先出的队列按层次进行遍历递进。
第一种方法借助了额外的空间消耗,复杂度相同的情况下,这是不大好的,然后第二种方法做了小优化。
coding
// /**
// * @param {number[][]} grid
// * @return {number}
// */
// var shortestBridge = function(grid) {
// let m = grid.length, n = grid[0].length;
// let level = 0;
// let curpoints = [];
// const points = [];
// function dfs(i , j) {
// if(i < 0 || j < 0 || i === m || j === n || grid[i][j] === 2) return;
// if(grid[i][j] === 0){
// points.push([i, j]);
// return;
// }
// grid[i][j] = 2;
// dfs(i - 1, j);
// dfs(i + 1, j);
// dfs(i, j - 1);
// dfs(i, j + 1);
// }
// // 寻找第一座岛屿
// for(let i = 0; i < m; ++ i) {
// if(grid[i].includes(1)){
// dfs(i, grid[i].indexOf(1));
// break;
// }
// }
// // bfs 寻找第二个岛屿, 并且把经过的0赋值为2
// while(points.length) {
// const [i, j] = points.shift();
// if(i < 0 || j < 0 || i >= m || j >= n || grid[i][j] === 2) {
// uplateLen();
// continue;
// }
// if (grid[i][j] === 1) { // 扩张到另一岛屿时,桥梁建成
// break;
// }
// if (grid[i][j] === 0) { // 存储下一轮扩张的坐标
// curpoints.push([i - 1, j], [i + 1, j], [i, j - 1], [i, j + 1]);
// }
// grid[i][j] = 2;
// uplateLen()
// }
// function uplateLen() {
// if(!points.length) {
// level++;
// points.push(...curpoints);
// curpoints = [];
// }
// }
// return level;
// };
/**
* @param {number[][]} grid
* @return {number}
*/
const direction = [-1, 0, 1, 0, -1]
var shortestBridge = function(grid) {
let m = grid.length, n = grid[0].length;
const points = [];
// 寻找第一座岛屿
for(let i = 0; i < m; ++ i) {
if(grid[i].includes(1)){
dfs(grid, points, i, grid[i].indexOf(1), m, n);
break;
}
}
// bfs 寻找第二个岛屿, 并且把经过的0赋值为2
let level = 0, dx, dy;
while(points.length) {
++level;
let n_points = points.length;
while(n_points--) {
const [i, j] = points.shift();
for(let k = 0; k < 4; k++) {
dx = i + direction[k];
dy = j + direction[k+1];
if(dx < 0 || dy < 0 || dx === m || dy === n || grid[dx][dy] === 2) {
continue;
}
if (grid[dx][dy] === 1) { // 扩张到另一岛屿时,桥梁建成
return level;
}
if (grid[dx][dy] === 0) { // 存储下一轮扩张的坐标
points.push([dx, dy]);
}
grid[dx][dy] = 2;
}
}
}
return level;
};
// 辅助函数
function dfs(grid, points, i , j, m, n) {
if(i < 0 || j < 0 || i === m || j === n || grid[i][j] === 2) return;
if(grid[i][j] === 0){
points.push([i, j]);
return;
}
grid[i][j] = 2;
dfs(grid, points, i - 1, j, m, n);
dfs(grid, points, i + 1, j, m, n);
dfs(grid, points, i, j - 1, m, n);
dfs(grid, points, i, j + 1, m, n);
}