leetcode刷题记录-1020. 飞地的数量 - 深度优先遍历

145 阅读2分钟

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

前言

今日的题目为中等,最开始以为是和之前一道题一样的思路,但是后来发现并不好做,最后转变了一下思路就变得很简单,有时候碰到了类似的题目如果发现不太对劲就要及时转变思路,换一个方向思考可能就会简单很多。

每日一题

今天的每日一题 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

题解

深度优先遍历

这道题和前几天做的黄金矿工有着异曲同工之妙,只是这道题的求法和黄金矿工是相反的。

leetcode刷题记录-1219. 黄金矿工 - 回溯算法

黄金矿工的思维是去遍历每一个单元格,当这个格子周围存在不为零的数就向前进,最后回去对比每一条不同路线的结果。

今天这道题利用相反的思维会更加的简便,我们可以从最外面一圈往里面遍历,存在值为1的格子就前进,并且把经过的格子值都变成0,最后只需要去统计值为1的格子的数量就可以了。

image.png

  1. 如上图 示例2 的例子当中,我们先去遍历周围一圈红色框,找到值为1的单元格。

  2. 从这个单元格开始,四周要是存在值为1的单元格就往前遍历,并且当前单元格值置为0。

image.png

image.png

  1. 知道遍历完周围一圈值为1的单元格,然后就可以去统计剩余值为1的单元格,就是题目需要的答案。
/**
 * @param {number[][]} grid
 * @return {number}
 */
var numEnclaves = function (grid) {
  let m = grid.length;
  let n = grid[0].length;
  let ans = 0;
  for (let i = 0; i < m; i++) {
    dfs(grid, i, 0);
    dfs(grid, i, n - 1);
  }
  for (let j = 0; j < n; j++) {
    dfs(grid, 0, j);
    dfs(grid, m - 1, j);
  }
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (grid[i][j] === 1) {
        ans++;
      }
    }
  }
  return ans;
};
var dfs = function (grid, x, y) {
  if (
    x < 0 ||
    y < 0 ||
    x >= grid.length ||
    y >= grid[0].length ||
    grid[x][y] === 0
  ) {
    return;
  }
  grid[x][y] = 0;
  dfs(grid, x + 1, y);
  dfs(grid, x - 1, y);
  dfs(grid, x, y + 1);
  dfs(grid, x, y - 1);
};

image.png