持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情
934. 最短的桥
给你一个大小为 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中恰有两个岛
解题思路
- 深度优先搜索
- 取得两个岛占据的区域的边缘点
- 从一个岛的边缘区域蔓延,直到和另外一个岛相交
- 蔓延的时候用栈保存每次蔓延后的边缘点,如果边缘点在另外一个岛出现了,蔓延的次数就是最少的0的次数
/**
* @param {number[][]} grid
* @return {number}
*/
var shortestBridge = function(grid) {
const isLand1 = new Set
let stack = new Set
const n = grid.length
const visited = Array.from({length: n}, () => new Array(n).fill(false))
const steps = [[0, 1], [0, -1], [1, 0], [-1,0] ]
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (visited[i][j] || !grid[i][j]) continue
if (!isLand1.size) {
getLan(isLand1, i, j)
} else {
getLan(stack, i, j)
}
}
}
function getLan(set, i, j) {
set.add(`${i}%${j}`)
visited[i][j] = true
let count = 0
for (const [x, y] of steps) {
const cx = i + x
const cy = j + y
if (cx < 0 || cx >= n || cy < 0 || cy >= n || visited[cx][cy] || !grid[cx][cy]) continue
count++
getLan(set, cx, cy)
}
if (count >= 4) {
set.delete(`${i}%${j}`)
}
}
let min = 0
while(stack.size) {
const newSet = new Set
for (const str of stack) {
const [x, y] = str.split('%')
for (const [dx, dy] of steps) {
const cx = x - 0 + dx
const cy = y - 0 + dy
if (isLand1.has(`${cx}%${cy}`)) return min
if (cx < 0 || cx >= n || cy < 0 || cy >= n || grid[cx][cy]) continue
newSet.add(`${cx}%${cy}`)
grid[cx][cy] = 1
}
}
stack = newSet
min++
}
return min
};