返回

LeetCode 417:太平洋大西洋水流问题——深度探索图论算法的魅力

前端

在计算机科学领域,图论算法扮演着举足轻重的角色,它让我们能够解决现实世界中错综复杂的互联问题。而 LeetCode 417:太平洋大西洋水流问题,正是图论算法魅力的完美展示。本文将带领你深入探索这道经典题目,了解其背后的算法思想和解题技巧。

引言

想象一座群山环绕的岛屿,太平洋在其东侧,大西洋在其西侧。雨水从天而降,汇聚成河流,奔流向海洋。我们想知道,哪些山顶的水最终将流入太平洋,哪些将流入大西洋。

问题

给你一个大小为 m x n 的整数矩阵 heights,其中 heights[i][j] 表示第 i 行、第 j 列山峰的高度。如果下雨,水会从这些山顶流向较低的山顶。如果水流到边界,那么就会流入太平洋或大西洋。

返回一个布尔矩阵 pacificAtlantic,其中 pacificAtlantic[i][j] = true,表示水从第 i 行、第 j 列山顶可以流入太平洋和大西洋;false 则表示只能流入其中一者或都不流入。

算法思想

解决这个问题的关键在于识别哪些山顶可以流入太平洋和大西洋,而图论算法正是解决此类问题的利器。

深度优先搜索 (DFS)

DFS 是一种递归算法,它沿着一条路径深入探索图,直到到达终点或遇到死胡同。在本题中,我们可以使用 DFS 来追踪从每个山顶流出的水流路径。

从太平洋和 大西洋的边界山顶开始,分别执行两个 DFS 遍历:

  • 太平洋遍历:从太平洋边界上的每个山顶出发,向四周较低的山顶递归搜索。
  • 大西洋遍历:从大西洋边界上的每个山顶出发,向四周较低的山顶递归搜索。

通过两个 DFS 遍历,我们可以标记出哪些山顶可以流入太平洋或大西洋。

广度优先搜索 (BFS)

BFS 是一种基于队列的算法,它从起点开始逐层扩展搜索范围。在本题中,我们可以使用 BFS 来优化 DFS 的搜索过程。

从太平洋和大西洋的边界山顶开始,分别执行两个 BFS 队列:

  • 太平洋队列:初始化队列,将太平洋边界上的山顶入队。
  • 大西洋队列:初始化队列,将大西洋边界上的山顶入队。

循环遍历队列,依次取出山顶并将其四周较低的山顶入队。直到队列为空,表示所有可流入太平洋或大西洋的山顶都被遍历完毕。

代码实现

def pacificAtlantic(heights):
    # 矩阵的行数和列数
    m, n = len(heights), len(heights[0])

    # 太平洋和 大西洋的可达矩阵,默认值为 False
    pacific = [[False] * n for _ in range(m)]
    atlantic = [[False] * n for _ in range(m)]

    def dfs(i, j, visited, prev_height):
        # 如果已经访问过或高度比之前访问的山顶低,则返回
        if visited[i][j] or heights[i][j] < prev_height:
            return

        # 标记为已访问
        visited[i][j] = True

        # 递归搜索四周山顶
        if i == 0 or j == 0:    # 太平洋边界
            pacific[i][j] = True
        if i == m - 1 or j == n - 1:  # 大西洋边界
            atlantic[i][j] = True
        if i > 0:
            dfs(i - 1, j, visited, heights[i][j])
        if i < m - 1:
            dfs(i + 1, j, visited, heights[i][j])
        if j > 0:
            dfs(i, j - 1, visited, heights[i][j])
        if j < n - 1:
            dfs(i, j + 1, visited, heights[i][j])

    # 从太平洋边界开始 DFS
    for i in range(m):
        dfs(i, 0, pacific, -1)  # 左边界
    for j in range(n):
        dfs(0, j, pacific, -1)  # 上边界

    # 从大西洋边界开始 DFS
    for i in range(m):
        dfs(i, n - 1, atlantic, -1)  # 右边界
    for j in range(n):
        dfs(m - 1, j, atlantic, -1)  # 下边界

    # 合并两个可达矩阵,得到最终结果
    result = [[pacific[i][j] and atlantic[i][j] for j in range(n)] for i in range(m)]

    return result

复杂度分析

  • 时间复杂度:O(mn),其中 mn 分别是矩阵的行数和列数。DFS 或 BFS 遍历的复杂度为 O(mn),合并两个矩阵的时间复杂度为 O(mn)
  • 空间复杂度:O(mn),用于存储可达矩阵和队列。

结论

LeetCode 417:太平洋大西洋水流问题是一道经典的图论算法题目。通过 DFS 或 BFS 算法,我们可以识别出哪些山顶可以流入太平洋和大西洋。掌握这些算法技巧,将大大提升我们在解决实际问题中的能力。

希望这篇文章能帮助你更深入地理解图论算法,并激发你对计算机科学的热爱。让我们继续探索算法世界的奥秘,解决更多精彩的问题!