1020. 飞地的数量(多源BFS)

308 阅读4分钟

「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战」。

每日刷题第45天 2021.02.12

1020. 飞地的数量

题目

  • 给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid 的边界。
  • 返回网格中无法在任意次数的移动中离开网格边界的陆地单元格的数量。

示例

  • 示例1 image.png
输入:grid = [[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]]
输出:3
解释:有三个 10 包围。一个 1 没有被包围,因为它在边界上。
  • 示例2 image.png
输入: grid = [[0,1,1,0],[0,0,1,0],[0,0,1,0],[0,0,0,0]]
输出: 0
解释: 所有 1 都在边界上或可以到达边界。

提示

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 500
  • grid[i][j] 的值为 0 或 1

解法

  • 解题思路:求解 -> 网格中无法在任意次数的移动中离开网格边界的陆地单元格的数量。
  • 分析:是否存在一些临界的条件,需要提前判断?
    • 存在:当长度为1或者为2的时候,因为外围都是直接接触到网格边界的因此,就可以直接输出0
  • 临界条件判断完毕,思考总的求解方法(bfs
  • 观察所给的样例并加以思考,发现当网格的边缘存在一个格子的时候,那么与其关联的其他格子也都是可以跨越边界的。因此,我们需要找出不能跨越边界的格子,只需要判断bfs遍历的这条路上,是否存在边界的格子。
    • 如果存在,那么与其关联的所有格子都一定能跨越边界。
    • 如果不存在,那么说明这些格子都不能跨越边界。

代码实现

  • 设当前走过的符合条件(在网格中值为1且之前没有访问过)的格子数为num,最终总的不能跨越边界的格子数为ans, bfs做过的路中是否存在边界格子(通过标记变量flag来记录,默认为false,表示不能跨越边界)
  • 循环遍历网格中的每一个格子,网格中值为1的时候,进入BFS遍历。
    • 注意:在首次进入的时候,需要将当前的元素的visited置为1,并且num++

优化思路

  • 优化:不需要visited数组的记录,可以直接将网格中值为1的,遍历过后,修改为值为0
  • 优化:可以直接遍历网格四周的元素,从这些元素入手,只有与这些元素相连的,才能够跨越边界。将这些可以跨越边界的值全部置为0,最后只需要统计网格中剩余的1的个数,就是不能跨越边界的格子数。
/**
 * @param {number[][]} grid
 * @return {number}
 */
var numEnclaves = function(grid) {
  // bfs遍历
  // 如果一直遍历到最后都没有一个 可以跨越边界的,则记录下前面遍历的个数
  // 否则 有一个可以跨越的,则直接返回,将个数不加给最后的总数
  // num ans   flag标记位 visited记录访问过的数组
  let lenR = grid.length; 
  let lenC = grid[0].length;
  let ans = 0;
  // 预判
  if(lenR == 1 || lenC == 1 || lenR == 2 || lenC == 2) return ans;
  // 正式开始操作
  let queue = [];
  let visited = new Array(lenR);
  for(let i = 0; i < lenR; i++){
    visited[i] = new Array(lenC).fill(0);
  }
  // console.log(visited);
  let num = 0;
  // false:未找到可以跨越的边界,vice versa
  let flag = false;
  function check(x, y){
    if(x < 0 || x >= lenR || y < 0 || y >= lenC) return false;
    if(visited[x][y] == 1 || grid[x][y] == 0) return false;
    return true;
  }
  let dx = [0,1,0,-1];
  let dy = [1,0,-1,0];
  // 自定义BFS方法
  function bfs(i, j) {
    queue.push([i,j]);
    // console.log(queue);
    while(queue.length) {
      let len = queue.length;
      for(let i = 0; i < len; i++) {
        let cur = queue.pop();
        let x = cur[0];
        let y = cur[1];
        if(x == 0 || y == 0 || x == lenR - 1 || y == lenC - 1){
          flag = true;
        }
        for(let j = 0; j < 4; j++) {
          let nx = dx[j] + x;
          let ny = dy[j] + y;
          if(check(nx,ny)){
            queue.push([nx,ny]);
            num++;
            visited[nx][ny] = 1;
          }
        }
      }
    }
  }
  for(let i = 0; i < lenR; i++) {
    for(let j = 0; j < lenC; j++) {
      if(grid[i][j] == 1 && visited[i][j] == 0){
        num++;
        visited[i][j] = 1;
        bfs(i, j);
        // 未找到可以跨越的边界
        if(flag == false){
          ans += num;
        }else {
          flag = false;
        }
        num = 0;
      }
    }
  }
  return ans;
};