持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第24天,点击查看活动详情
每日刷题 2022.10.25
- leetcode原题链接:leetcode.cn/problems/sh…
- 难度:中等
题目
- 给你一个大小为 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].length
2 <= n <= 100
grid[i][j]
为0
或1
grid
中恰有两个岛
解题思路
- 经典的
bfs
所有的节点的权值都为1
,但如果我们把某些点的权值视为0
,即经过这个点不需要花销,则转变为了0-1 bfs
- 经典的
bfs
使用一个队列,队列中层级小的点在队列前面,新的节点在队尾入队,这样可以优先遍历层级小的节点 0-1 bfs
使用双端队列,新节点入队时,若权值为0
则入对头,否则入队尾,这样可以优先处理权值为0
的节点- 此题中值为
1
的点权值为0
,值为0
的点权值为1
- 先找到一个值为
1
的点视为起点,然后利用0-1 bfs
计算所有点到他的最短距离(即相连需要反转的0
的最小个数) - 时间复杂度:
O(n^2)
空间复杂度:O(n^2)
其他的解法
- 并查集+ 双端
bfs
AC
代码
/**
* @param {number[][]} grid
* @return {number}
*/
var shortestBridge = function (grid) {
const d = [-1, 0, 1, 0, -1];
const n = grid.length;
const que = [];
const dfs = (x, y) => {
if (x < 0 || y < 0 || x >= n || y >= n || grid[x][y] !== 1) return;
que.push([x, y]);
grid[x][y] = 11; //标记为岛1的点,剩下为1的都是岛2 的点
for (let di = 0; di < 4; di++) dfs(x + d[di], y + d[di + 1]);
};
for (let i = 0; i < n; i++) {
let breakFlag = false;
for (let j = 0; j < n; j++) {
if (grid[i][j] === 1) {
dfs(i, j);
breakFlag = true;
break;
}
}
if (breakFlag) break;
}
let step = 0;
//BFS
while (que.len !== 0) {
const sz = que.length;
for (let k = 0; k < sz; k++) {
const cur = que.shift(); //从队列头部取才保证是在岛1的外层
for (let l = 0; l < 4; l++) {
const dx = cur[0] + d[l];
const dy = cur[1] + d[l + 1];
if (dx >= 0 && dy >= 0 && dx < n && dy < n) {
if (grid[dx][dy] === 0) {
//是海就是边缘,加入队列用于下一次
que.push([dx, dy]);
grid[dx][dy] = 2; //标记为访问过
} else if (grid[dx][dy] === 1)
//遇到 岛2 的点了
return step;
}
}
}
step++;
}
return 0; //其实题目确保有路的话是不会走到这里的
};