巧用广度优先搜索算法,畅游 LeetCode 题海
2023-10-02 12:37:56
广度优先搜索:图遍历的强大算法
探索图的奥秘
图是一种数据结构,用于表示对象之间的关系,在现实生活中有着广泛的应用,例如社交网络、地图导航和计算机网络。广度优先搜索(BFS)是一种遍历图的算法,以层层展开的方式探索图中的节点。
BFS 的原理
BFS 的核心思想是逐层探索图中的节点。算法从一个起始节点开始,访问与其相邻的节点,然后再访问与这些节点相邻的节点,以此类推。就像剥洋葱一样,BFS 一层一层向外扩展,直到遍历完整个图。
BFS 的优势
- 保证最短路径: BFS 总是能找到从起始节点到其他节点的最短路径。
- 易于实现: BFS 的实现非常简单,只需要一个队列数据结构即可。
- 适用于无权图: BFS 不需要权重信息,因此可以应用于没有权重的图中。
BFS 的应用
BFS 在 LeetCode 等算法竞赛平台上有广泛的应用,其中一些经典题型包括:
- 图的连通性判断: BFS 可以用来判断一个图是否连通。
- 最短路径查找: BFS 可以用来查找从起始节点到其他节点的最短路径。
- 拓扑排序: BFS 可以用来对无环图进行拓扑排序。
- 迷宫求解: BFS 可以用来求解迷宫,找到从起点到终点的最短路径。
LeetCode 广度优先搜索实战
案例 1:判断图的连通性
bool isConnected(vector<vector<int>>& graph) {
queue<int> q;
vector<bool> visited(graph.size(), false);
q.push(0); // 从节点 0 开始访问
while (!q.empty()) {
int node = q.front();
q.pop();
if (visited[node]) continue;
visited[node] = true;
for (int neighbor : graph[node]) {
if (!visited[neighbor]) {
q.push(neighbor);
}
}
}
for (bool flag : visited) {
if (!flag) return false;
}
return true;
}
案例 2:最短路径查找
int shortestPath(vector<vector<int>>& graph, int start, int end) {
queue<int> q;
vector<int> distance(graph.size(), INT_MAX);
q.push(start);
distance[start] = 0;
while (!q.empty()) {
int node = q.front();
q.pop();
if (node == end) return distance[node];
for (int neighbor : graph[node]) {
if (distance[neighbor] == INT_MAX) {
distance[neighbor] = distance[node] + 1;
q.push(neighbor);
}
}
}
return -1; // 未找到路径
}
案例 3:拓扑排序
vector<int> topologicalSort(vector<vector<int>>& graph) {
queue<int> q;
vector<int> inDegree(graph.size(), 0);
for (vector<int>& neighbors : graph) {
for (int neighbor : neighbors) {
inDegree[neighbor]++;
}
}
for (int i = 0; i < graph.size(); i++) {
if (inDegree[i] == 0) q.push(i);
}
vector<int> result;
while (!q.empty()) {
int node = q.front();
q.pop();
result.push_back(node);
for (int neighbor : graph[node]) {
inDegree[neighbor]--;
if (inDegree[neighbor] == 0) q.push(neighbor);
}
}
return result;
}
案例 4:迷宫求解
bool findPath(vector<vector<char>>& maze, int startRow, int startCol, int endRow, int endCol) {
queue<pair<int, int>> q;
vector<vector<bool>> visited(maze.size(), vector<bool>(maze[0].size(), false));
q.push({startRow, startCol});
while (!q.empty()) {
pair<int, int> node = q.front();
q.pop();
int row = node.first;
int col = node.second;
if (row == endRow && col == endCol) return true;
if (!visited[row][col]) {
visited[row][col] = true;
// 向上下左右四个方向探索
if (row > 0 && maze[row - 1][col] != '#') q.push({row - 1, col});
if (row < maze.size() - 1 && maze[row + 1][col] != '#') q.push({row + 1, col});
if (col > 0 && maze[row][col - 1] != '#') q.push({row, col - 1});
if (col < maze[0].size() - 1 && maze[row][col + 1] != '#') q.push({row, col + 1});
}
}
return false;
}
结论
广度优先搜索是一种强大且易于实现的算法,广泛应用于图的遍历和相关问题中。掌握 BFS 的原理和实现,可以帮助你轻松解决 LeetCode 等算法竞赛平台上的各种图算法问题。
常见问题解答
1. BFS 和深度优先搜索(DFS)的区别是什么?
BFS 和 DFS 是两种不同的图遍历算法。BFS 逐层探索图中的节点,而 DFS 沿深度优先的路径探索图中的节点。BFS 通常用于查找最短路径,而 DFS 用于查找环和连通组件。
2. BFS 如何保证找到最短路径?
BFS 总是选择与当前节点相邻的节点,逐层向外扩展。由于最短路径的长度最短,因此 BFS 遍历的第一个到达目标节点的路径一定是最短路径。
3. BFS 可以应用于加权图吗?
BFS 本身不适用于加权图,因为它不考虑边权重。要应用于加权图,需要使用迪杰斯特拉算法或 A* 算法。
4. BFS 可以判断一个图是否为无环图吗?
不能。BFS 不能直接判断一个图是否为无环图。需要使用拓扑排序算法或 DFS 算法进行判断。
5. BFS 可以用来查找图中的所有环吗?
不能。BFS 只能找到图中的简单环(不包含重复的节点)。要查找图中的所有环,需要使用更加复杂的算法,例如 Kosaraju 算法或 Tarjan 算法。