持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 15 天,点击查看活动详情。
最短的桥
原题地址
给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。
岛 是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid 中 恰好存在两座岛 。
你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛 。
返回必须翻转的 0 的最小数目。
示例 1:
输入:grid = [[0,1],[1,0]]
输出:1
示例 2:
输入:grid = [[0,1,0],[0,0,0],[0,0,1]]
输出:2
示例 3:
输入:grid = [[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]]
输出:1
提示:
n == grid.length == grid[i].length2 <= n <= 100grid[i][j]为0或1grid中恰有两个岛
思路分析
- 题目中要求两座岛屿合成一座岛屿,我们就要考虑如何将两个岛屿合并成一座岛屿;
- 先使用 DFS 找到其中一座岛屿,并且将岛屿里面的所有坐标都存入 res 中;
- 再使用 BFS 从 DFS 中找到的岛屿终的点去寻找最近的坐标为1即为陆地的点;
- 若最后找不到,返回 -1 即可。
AC 代码
/**
* @param {number[][]} grid
* @return {number}
*/
var shortestBridge = function(grid) {
const r = grid.length
const c = grid[0].length
const directions = [
[0, 1],
[0, -1],
[1, 0],
[-1, 0],
]
const res = []
const dfs = (i, j) => {
// 1代表陆地 岛是由四面相连的 1 形成的一个最大组
if (i < 0 || i >= r || j < 0 || j >= c || grid[i][j] !== 1) return
// 标记小岛2
grid[i][j] = 2
// 初始化 res(记录小岛2的坐标)
res.push([i, j])
for (let [x, y] of directions) {
dfs(i + x, j + y)
}
}
const bfs = () => {
let count = 0
while (res.length) {
let len = res.length
count++
while (len--) {
const [i, j] = res.shift()
// 向四周遍历
for (let [x, y] of directions) {
const newI = i + x
const newJ = j + y
if (newI >= 0 && newI < r && newJ >= 0 && newJ < c) {
// 找到小岛1,直接返回
// 找到空白,继续前进搜寻
if (grid[newI][newJ] === 1) {
return count - 1
} else if (grid[newI][newJ] === 0) {
// 先把它融入小岛1中避免重复访问到
grid[newI][newJ] = 2
res.push([newI, newJ])
}
}
}
}
}
};
for (let i = 0; i < r; i++) {
for (let j = 0; j < c; j++) {
if (grid[i][j] === 1) {
dfs(i, j)
return bfs()
}
}
}
return -1
};
结果:
- 执行结果: 通过
- 执行用时:92 ms, 在所有 JavaScript 提交中击败了48.94%的用户
- 内存消耗:47.2 MB, 在所有 JavaScript 提交中击败了81.92%的用户
- 通过测试用例:97 / 97