题目:LC785 判断二分图
二分图:指每条边都连接着两个不同区域。
等价:
边两端的节点不同颜色,只有两个颜色。
解题
解法1:dfs
深度优先遍历,记录访问过的节点和颜色,遍历图节点
如果访问过且颜色和源节点一样,就不是二分图
如果没访问过,就赋予不同的颜色。
遍历完没有冲突就是二分图。
class Solution {
public:
bool res; // 是不是二分图
vector<bool> visited;
vector<bool> color; // 记录颜色
bool isBipartite(vector<vector<int>>& graph) {
int n = graph.size();
res = true;
visited = vector<bool>(n, false);
color = vector<bool>(n, false);
for (int i = 0; i < n; i++) {
if (!visited[i])
trace(graph, i);
}
return res;
}
void trace(vector<vector<int>>& graph, int now) {
if (!res) return;
visited[now] = true;
for (auto next : graph[now]) {
if (!visited[next]) {
color[next] = !color[now];
trace(graph, next);
} else {
if (color[next] == color[now])
res = false;
}
}
}
};
复杂度
- 时间:O(n+edge)
- 空间:O(n)
解法2:并查集
如果边的两端节点已经属于同一个集合,就不是二分图。因为二分图的定义就是边的两端属于不同集合。
1. 遍历所有节点,把当前节点的临边节点放在一个集合里,因为当前节点一定要与临边节点在不同集合,也就是临边节点在同一个集合。
2. 最后再检查一遍,当前节点 有没有和临边节点在同一个集合。
class Solution {
public:
vector<int> fa;
int father(int a) {
if (a != fa[a])
fa[a] = father(fa[a]);
return fa[a];
}
void unionn(int a, int b) { fa[father(a)] = father(b); }
bool same(int a, int b) { return father(a) == father(b); }
bool isBipartite(vector<vector<int>>& graph) {
int n = graph.size();
for (int i = 0; i < n; ++i) {
fa.push_back(i);
}
for (int i = 0; i < n; ++i) {
for (int j = 1; j < graph[i].size(); ++j) {
unionn(graph[i][0], graph[i][j]);
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < graph[i].size(); ++j) {
if (same(i, graph[i][j]))
return false;
}
}
return true;
}
};
复杂度
- 时间:O(n+edge)
- 空间:O(n)