前端算法必刷题系列[77]|8月更文挑战

753 阅读3分钟

这个系列没啥花头,就是纯 leetcode 题目拆解分析,不求用骚气的一行或者小众取巧解法,而是用清晰的代码和足够简单的思路帮你理清题意。让你在面试中再也不怕算法笔试。

144. 岛屿数量 (number-of-islands)

标签

  • 染色
  • 中等

题目

leetcode 传送门

这里不贴题了,leetcode打开就行,题目大意:

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1

输入:grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]
输出:1

示例 2

输入:grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出:3

基本思路

其实这个问题就是典型的染色问题

我们其实就是遍历所有位置,先判断是否是陆地,如果是陆地就往4个方向探索并把陆地沉掉,附近连着的陆地都被沉掉了,计算数量就可以加 1。思路还是比较简单的,就是染色方式可以有多种。

编码步骤:

  1. 我们要计算岛屿数量,需要有个count变量
  2. 开始遍历所有格子,发现0,则不做操作
  3. 如果是 1, count++, 表明这是陆地,那么这块陆地有多大,则可以用 DFS/BFS 继续探索它的上下左右,发现是陆地就染上色,最后都探索到边界,说明这个岛都被染色了 然后直接把所有岛沉了,(染色格子 从 1 => 0),继续向下遍历。
  4. 到最后 count是算出来了 ,格子里都变成了 0

对 DFS 和 BFS 不熟悉 可以看这篇 DFS/BFS

写法实现

DFS

var numIslands = function(grid) {
  let count = 0, rows = grid.length, cols = grid[0].length
  // 四个方向的移动配置
  const direction = [[0, 1], [0, -1], [1, 0], [-1, 0]]
  const dfs = (i, j) => {
    for ([dx, dy] of direction) {
      // 走过步数后的坐标
      let nowI = i + dx, nowJ = j + dy
      // 不超过边界的,且是 1的 染色置 0
      if (nowI >= 0 && nowJ >= 0 && nowI < rows && nowJ < cols && grid[nowI][nowJ] === '1') {
        grid[nowI][nowJ] = '0'
        // 继续递归查找
        dfs(nowI, nowJ)
      }
    }
  }

  // 开始遍历
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      if (grid[i][j] === '1') {
        count++
        // 染色沉岛
        dfs(i, j)
      }
    }
  }
  return count
};

let grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]

console.log(numIslands(grid))

BFS

类似的,用广度优先做染色,类比二叉树层序遍历你会有新的收获。

var numIslands = function(grid) {
  let count = 0, rows = grid.length, cols = grid[0].length
  const direction = [[0, 1], [0, -1], [1, 0], [-1, 0]]
  // 做 BFS 需要一个辅助队列 queue
  let queue = []

  const bfs = () => {
    while (queue.length > 0) {
      let [i, j] = queue.shift()
      for ([dx, dy] of direction) {
        let [nowI, nowJ] = [i + dx, j + dy]
        if (nowI >= 0 && nowJ >= 0 && nowI < rows && nowJ < cols && grid[nowI][nowJ] === '1') {
          grid[nowI][nowJ] = '0'
          // 推入下一个种子节点 (类似层序遍历的下一层)
          queue.push([nowI, nowJ])
        }
      }
    }
  }

  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      if (grid[i][j] === '1') {
        count++
        // 染色沉岛
        grid[i][j] = '0'
        // 推入一个种子做 bfs 搜索
        queue.push([i, j])
        bfs()
      }
    }
  }
  return count
}

let grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]

console.log(numIslands(grid))

拓展

还有一种查并集的方式,比较复杂,建议先了解查并集是什么再看解决方式 岛屿问题

另外向大家着重推荐下这个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友 Or 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考