算法小白如何快速入门:用 通俗易懂 的方式掌握「广度优先搜索」「深度优先搜索」和「并查集」
2023-12-15 13:33:38
广度优先搜索与深度优先搜索:揭秘算法世界的两大巨头
算法,计算机科学的基石,对于程序员来说,更是必备技能。然而,算法的学习之旅往往布满荆棘,晦涩难懂的概念、复杂的数学知识,将许多初学者拒之门外。
但别担心!我们将为您开启一扇通往算法世界的门,从三个最基本、最常用的算法说起——广度优先搜索(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)
常见问题解答
-
广度优先搜索和深度优先搜索有什么区别?
- BFS层层推进,保证探索的宽度,而DFS深入挖掘,保证探索的深度。
-
并查集有什么作用?
- 并查集用于管理集合,提供集合合并和查找元素所属集合的操作。
-
如何解决「太平洋大西洋水流」问题?
- 使用广度优先搜索,从太平洋和大西洋向内探索,找出可以同时到达两边的区域。
-
BFS和DFS的适用场景有哪些?
- BFS适用于寻找最短路径或最短覆盖等问题,而DFS适用于寻找回路或拓扑排序等问题。
-
如何提高算法效率?
- 优化数据结构的选择,减少时间和空间复杂度。