Sealessland logo Sealessland
Interview Prep

面试手撕图论板子:建图 / BFS / 网格 / 拓扑 / 并查集 / 最短路

图论面试板子题单:邻接表建图、BFS/DFS 遍历、网格图 dx dy、拓扑排序、并查集、BFS 与 Dijkstra 最短路,附推荐刷题顺序和最小无痛版 15 题。

面试手撕图论板子:建图 / BFS / 网格 / 拓扑 / 并查集 / 最短路

给你一套专门练图论板子的 LeetCode 题单。目标不是刷玄学难题,而是把这些板子练熟:

邻接表建图、BFS、DFS、网格 BFS/DFS、拓扑排序、并查集、最短路。


0. 入门:先练”图怎么存”

题目

题号题名练什么
797所有可能的路径有向图邻接表 + DFS
841钥匙和房间邻接表 + BFS/DFS
1971寻找图中是否存在路径无向图建图 + BFS/DFS
1791找出星型图的中心节点边的理解

先把这个板子练熟:

vector<vector<int>> g(n);

for (int i = 0; i < edges.size(); i++) {
    int u = edges[i][0];
    int v = edges[i][1];

    g[u].push_back(v);
}

无向图就是:

g[u].push_back(v);
g[v].push_back(u);

1. BFS / DFS 基础遍历

题目

题号题名推荐做法
547省份数量DFS / BFS
841钥匙和房间DFS / BFS
1971寻找图中是否存在路径BFS
2316统计无向图中无法互相到达点对数DFS 统计连通块大小

核心模板:

vector<int> visited(n, 0);
queue<int> q;

q.push(start);
visited[start] = 1;

while (!q.empty()) {
    int cur = q.front();
    q.pop();

    for (int i = 0; i < g[cur].size(); i++) {
        int next = g[cur][i];

        if (visited[next] == 1) {
            continue;
        }

        visited[next] = 1;
        q.push(next);
    }
}

2. 网格图:dx dy 板子

这是面试最常见的一类。

题目

题号题名练什么
200岛屿数量网格 DFS/BFS
695岛屿的最大面积DFS 统计面积
994腐烂的橘子多源 BFS
54201 矩阵多源 BFS
733图像渲染简单 Flood Fill
130被围绕的区域从边界反向 DFS/BFS
1091二进制矩阵中的最短路径八方向 BFS
417太平洋大西洋水流问题反向 DFS/BFS

四方向板子:

int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};

for (int k = 0; k < 4; k++) {
    int nx = x + dx[k];
    int ny = y + dy[k];

    if (nx < 0 || nx >= n || ny < 0 || ny >= m) {
        continue;
    }

    // 处理 grid[nx][ny]
}

八方向板子:

int dx[8] = {1, 1, 1, 0, 0, -1, -1, -1};
int dy[8] = {1, 0, -1, 1, -1, 1, 0, -1};

3. 拓扑排序:课程表这一类

这是你现在正在练的。

题目

题号题名练什么
207课程表拓扑排序判环
210课程表 II输出拓扑序
802找到最终的安全状态反图 + 拓扑 / DFS 判环
1462课程表 IV传递依赖
310最小高度树拓扑剥叶子
1203项目管理分组拓扑排序,偏难

最核心先刷:

207 -> 210 -> 802 -> 310

拓扑排序模板:

queue<int> q;
vector<vector<int>> g(n);
vector<int> indeg(n, 0);

for (int i = 0; i < edges.size(); i++) {
    int u = edges[i][0];
    int v = edges[i][1];

    g[u].push_back(v);
    indeg[v]++;
}

for (int i = 0; i < n; i++) {
    if (indeg[i] == 0) {
        q.push(i);
    }
}

int learned = 0;

while (!q.empty()) {
    int learning = q.front();
    q.pop();

    learned++;

    for (int i = 0; i < g[learning].size(); i++) {
        int toBeLearn = g[learning][i];

        indeg[toBeLearn]--;

        if (indeg[toBeLearn] == 0) {
            q.push(toBeLearn);
        }
    }
}

return learned == n;

4. 并查集:连通性专用

并查集适合处理:

谁和谁属于同一个集合。

题目

题号题名练什么
547省份数量并查集入门
684冗余连接找环
1971寻找图中是否存在路径连通性
1319连通网络的操作次数连通块数量
990等式方程的可满足性字符并查集
721账户合并字符串并查集,偏实战

板子:

class UnionFind {
public:
    vector<int> parent;

    UnionFind(int n) {
        parent.resize(n);

        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }

    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }

        return parent[x];
    }

    void merge(int a, int b) {
        int pa = find(a);
        int pb = find(b);

        if (pa != pb) {
            parent[pa] = pb;
        }
    }
};

5. 最短路:BFS / Dijkstra

普通无权图最短路,用 BFS。 带权正边最短路,用 Dijkstra。

BFS 最短路题

题号题名练什么
1091二进制矩阵中的最短路径八方向 BFS
752打开转盘锁状态图 BFS
127单词接龙状态图 BFS,偏难
433最小基因变化BFS

Dijkstra 题

题号题名练什么
743网络延迟时间Dijkstra 模板
1514概率最大的路径Dijkstra 变形
1631最小体力消耗路径Dijkstra on Grid
787K 站中转内最便宜的航班最短路变形,偏难

Dijkstra 先不用急,等你 BFS / 拓扑 / 并查集稳了再练。


6. DFS 判环

拓扑排序可以 BFS 做,DFS 也能判环。你可以后面补。

题目

题号题名练什么
207课程表DFS 三色标记判环
802找到最终的安全状态DFS 判环
1059从始点到终点的所有路径DFS 判环,偏难

三色标记:

0 = 没访问
1 = 正在访问
2 = 访问完成

推荐刷题顺序

不要一上来全刷,按这个顺序来:

第一组:邻接表 + 普通 BFS/DFS
841 -> 1971 -> 547

第二组:网格图 dx dy
733 -> 200 -> 695 -> 994 -> 542

第三组:拓扑排序
207 -> 210 -> 802 -> 310

第四组:并查集
547 -> 1971 -> 684 -> 1319 -> 990

第五组:状态图 BFS
752 -> 1091 -> 433 -> 127

第六组:Dijkstra
743 -> 1631 -> 1514

最小无痛版题单

要是你只想快速掌握面试图论板子,刷这 15 道就够有感觉:

841 钥匙和房间
1971 寻找图中是否存在路径
547 省份数量
733 图像渲染
200 岛屿数量
695 岛屿的最大面积
994 腐烂的橘子
542 01 矩阵
207 课程表
210 课程表 II
802 找到最终的安全状态
684 冗余连接
1319 连通网络的操作次数
752 打开转盘锁
743 网络延迟时间

你现在最该练的是:

207 课程表
210 课程表 II
841 钥匙和房间
200 岛屿数量
994 腐烂的橘子

这五道刷完,图论最基础的几个板子就真的立住了。