返回

LeetCode 岛屿数量学习笔记

前端

大家好,今天给大家分享下一道 LeetCode 中等难度 的题目200. 岛屿数量。这道题考察的是 Graph 的应用,如何使用 DFS 来 BFS 遍历节点。

题目分析

给定一个由 0 和 1 组成的二维网格,其中 0 表示水,1 表示陆地。一个岛屿是由相邻的 1 (水平或垂直) 组成的区域。请计算网格中岛屿的数量。

例如,给定如下网格:

11110
11010
11000
00000

岛屿的数量为 1 。

解法一:DFS

深度优先搜索(DFS)是一种遍历 Graph 的算法。它从一个节点开始,并沿着一条边走到另一个节点,然后继续遍历该节点的邻接节点,直到没有更多节点可供遍历。DFS 的实现可以使用栈数据结构。

对于这道题,我们可以使用 DFS 来遍历网格中的节点。当我们遇到一个 1 时,我们就从这个节点开始 DFS,并把这个节点的所有相邻节点加入栈中。然后,我们继续遍历栈中的节点,直到栈为空。

def num_islands_dfs(grid):
  """
  计算网格中岛屿的数量。

  参数:
    grid: 一个由 0 和 1 组成的二维网格。

  返回:
    岛屿的数量。
  """

  if not grid:
    return 0

  # 初始化岛屿数量为 0。
  num_islands = 0

  # 遍历网格中的每个节点。
  for i in range(len(grid)):
    for j in range(len(grid[0])):
      # 如果当前节点是 1,则表明它是陆地。
      if grid[i][j] == 1:
        # 从当前节点开始 DFS。
        dfs(grid, i, j)

        # 岛屿数量加 1。
        num_islands += 1

  return num_islands


def dfs(grid, i, j):
  """
  从 (i, j) 节点开始 DFS。

  参数:
    grid: 一个由 0 和 1 组成的二维网格。
    i: 当前节点的行索引。
    j: 当前节点的列索引。
  """

  # 如果当前节点越界,或者不是陆地,则返回。
  if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] == 0:
    return

  # 将当前节点标记为已访问。
  grid[i][j] = 0

  # 遍历当前节点的相邻节点。
  dfs(grid, i - 1, j)  # 上
  dfs(grid, i + 1, j)  # 下
  dfs(grid, i, j - 1)  # 左
  dfs(grid, i, j + 1)  # 右

解法二:BFS

广度优先搜索(BFS)也是一种遍历 Graph 的算法。它从一个节点开始,并把这个节点的所有相邻节点加入队列中。然后,我们从队列中取出一个节点,并把这个节点的所有相邻节点加入队列中。我们继续重复这个过程,直到队列为空。

对于这道题,我们可以使用 BFS 来遍历网格中的节点。当我们遇到一个 1 时,我们就从这个节点开始 BFS,并把这个节点的所有相邻节点加入队列中。然后,我们继续从队列中取出节点,并把这个节点的所有相邻节点加入队列中。直到队列为空,我们就可以得到网格中岛屿的数量。

def num_islands_bfs(grid):
  """
  计算网格中岛屿的数量。

  参数:
    grid: 一个由 0 和 1 组成的二维网格。

  返回:
    岛屿的数量。
  """

  if not grid:
    return 0

  # 初始化岛屿数量为 0。
  num_islands = 0

  # 遍历网格中的每个节点。
  for i in range(len(grid)):
    for j in range(len(grid[0])):
      # 如果当前节点是 1,则表明它是陆地。
      if grid[i][j] == 1:
        # 从当前节点开始 BFS。
        bfs(grid, i, j)

        # 岛屿数量加 1。
        num_islands += 1

  return num_islands


def bfs(grid, i, j):
  """
  从 (i, j) 节点开始 BFS。

  参数:
    grid: 一个由 0 和 1 组成的二维网格。
    i: 当前节点的行索引。
    j: 当前节点的列索引。
  """

  # 创建一个队列。
  queue = [(i, j)]

  # 遍历队列中的每个节点。
  while queue:
    # 从队列中取出一个节点。
    i, j = queue.pop(0)

    # 如果当前节点越界,或者不是陆地,则跳过。
    if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]) or grid[i][j] == 0:
      continue

    # 将当前节点标记为已访问。
    grid[i][j] = 0

    # 把当前节点的所有相邻节点加入队列中。
    queue.append((i - 1, j))  # 上
    queue.append((i + 1, j))  # 下
    queue.append((i, j - 1))  # 左
    queue.append((i, j + 1))  # 右

总结

这道题考察的是 Graph 的应用,如何使用 DFS 来 BFS 遍历节点。DFS 和 BFS 都是遍历 Graph 的两种常见算法,它们各有优缺点。DFS 的优点是空间复杂度低,但缺点是可能会陷入死循环。BFS 的优点是空间复杂度高,但缺点是不会陷入死循环。对于这道题,我们可以使用 DFS 和 BFS 来解决,但使用 BFS 的解法更简单一些。