返回

算法小白如何快速入门:用 通俗易懂 的方式掌握「广度优先搜索」「深度优先搜索」和「并查集」

后端

广度优先搜索与深度优先搜索:揭秘算法世界的两大巨头

算法,计算机科学的基石,对于程序员来说,更是必备技能。然而,算法的学习之旅往往布满荆棘,晦涩难懂的概念、复杂的数学知识,将许多初学者拒之门外。

但别担心!我们将为您开启一扇通往算法世界的门,从三个最基本、最常用的算法说起——广度优先搜索(BFS)、深度优先搜索(DFS)和并查集。它们简单易懂,却有着广泛的应用,是算法学习的坚实基础。

广度优先搜索:逐层探索,步步为营

广度优先搜索,顾名思义,它像一个谨慎的探险家,一步一个脚印地探索图中的每一个角落。从某个顶点出发,它首先拜访该顶点的所有相邻顶点,然后依次拜访这些顶点的相邻顶点,如此循环往复,直到图中所有顶点都纳入版图。

BFS的实现,就如同我们小时候玩的迷宫游戏,使用队列来储存待探索的顶点。我们从起始顶点开始,将其放入队列,然后依次从队列中取出顶点,并将其相邻顶点也加入队列中。这样,我们就能层层推进,将图中所有顶点收入囊中。

代码示例:

def bfs(graph, start):
    queue = [start]
    visited = set()
    while queue:
        current = queue.pop(0)
        if current in visited:
            continue
        visited.add(current)
        for neighbor in graph[current]:
            queue.append(neighbor)

深度优先搜索:深入挖掘,一探究竟

深度优先搜索,则像一位无畏的冒险家,沿着一条路径一路前行,直到走投无路,再回过头来探索其他分支。它从某个顶点出发,沿着一条路径不断深入,直到到达终点,然后回溯到上一个未探索的岔路口,继续深入。如此反复,直到图中所有顶点都被遍历完毕。

DFS的实现,则如同我们解决迷宫的另一条道路,使用栈来储存待探索的顶点。我们从起始顶点开始,将其压入栈中,然后依次从栈顶弹出顶点,并将其相邻顶点也压入栈中。这样,我们就能沿着一条路径深入探索,直到穷途末路。

代码示例:

def dfs(graph, start):
    stack = [start]
    visited = set()
    while stack:
        current = stack.pop()
        if current in visited:
            continue
        visited.add(current)
        for neighbor in graph[current]:
            stack.append(neighbor)

并查集:集合管理,游刃有余

并查集,则像一位集合管理大师,它能将一组元素划分为若干个互不相交的子集,并提供两种关键操作——合并子集和查找元素所属子集。

并查集的实现,依赖于一个数组,它将每个元素存储在数组中,并使用一个父节点字段来表示该元素所属的子集。当我们需要合并两个子集时,只需要将这两个子集的父节点指向同一个父节点即可。当我们需要查找某个元素所属子集时,只需要沿着父节点字段向上查找,直到找到根节点即可。

代码示例:

class DisjointSetUnion:
    def __init__(self):
        self.parents = {}

    def find(self, x):
        if x not in self.parents:
            self.parents[x] = x
        if self.parents[x] != x:
            self.parents[x] = self.find(self.parents[x])
        return self.parents[x]

    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        if root_x != root_y:
            self.parents[root_y] = root_x

算法应用:太平洋大西洋水流

现在,让我们将这些算法应用到一个实际问题——「太平洋大西洋水流」中。

问题

给定一个二维网格,其中每个单元格的值表示该单元格所在位置的海拔高度。太平洋和

解题思路:

我们可以使用广度优先搜索来解决这个问题。从太平洋和

代码实现:

def pacific_atlantic(matrix):
    if not matrix or not matrix[0]:
        return []
    m, n = len(matrix), len(matrix[0])
    pacific = set()
    atlantic = set()
    directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    
    def bfs(start, ocean):
        queue = [(start[0], start[1])]
        while queue:
            i, j = queue.pop(0)
            if (i, j) in ocean:
                continue
            ocean.add((i, j))
            for d in directions:
                x, y = i + d[0], j + d[1]
                if 0 <= x < m and 0 <= y < n and matrix[x][y] >= matrix[i][j]:
                    queue.append((x, y))
    
    for i in range(m):
        bfs((i, 0), pacific)
        bfs((i, n - 1), atlantic)
    
    for j in range(n):
        bfs((0, j), pacific)
        bfs((m - 1, j), atlantic)
    
    return list(pacific & atlantic)

常见问题解答

  1. 广度优先搜索和深度优先搜索有什么区别?

    • BFS层层推进,保证探索的宽度,而DFS深入挖掘,保证探索的深度。
  2. 并查集有什么作用?

    • 并查集用于管理集合,提供集合合并和查找元素所属集合的操作。
  3. 如何解决「太平洋大西洋水流」问题?

    • 使用广度优先搜索,从太平洋和大西洋向内探索,找出可以同时到达两边的区域。
  4. BFS和DFS的适用场景有哪些?

    • BFS适用于寻找最短路径或最短覆盖等问题,而DFS适用于寻找回路或拓扑排序等问题。
  5. 如何提高算法效率?

    • 优化数据结构的选择,减少时间和空间复杂度。