返回

巧用广度优先搜索算法,畅游 LeetCode 题海

见解分享

广度优先搜索:图遍历的强大算法

探索图的奥秘

图是一种数据结构,用于表示对象之间的关系,在现实生活中有着广泛的应用,例如社交网络、地图导航和计算机网络。广度优先搜索(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 算法。