题目详情
给定一个无向图graph,当这个图为二分图时返回true。
如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。
graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。
示例 1:
输入: [[1,3], [0,2], [1,3], [0,2]]
输出: true
解释:
无向图如下:
0----1
| |
| |
3----2
我们可以将节点分成两组: {0, 2} 和 {1, 3}。
示例 2:
输入: [[1,2,3], [0,2], [0,1,3], [0,2]]
输出: false
解释:
无向图如下:
0----1
| \ |
| \ |
3----2
我们不能将节点分割成两个独立的子集。
注意:
——题目难度:中等
首先先介绍一下 自环边 和 平行边。
在图论中,存在两种相对比较特殊的边:
(1)自环边(self-loop):一个顶点到这个顶点自身的边
(2)平行边(parallel-edges):两个顶点之间存在多条边相连接。
无论是自环边还是平行边,在很多时候也是有意义的。最典型的,如:对于交通运输来说,从 A 城市到 B 城市可能有不止一条路,可能有三条路,在这种情况下,平行边就非常有意义 但与此同时,自环边和平行边,会加大算法设计的难度,而且在很多情况下,我们真正关心的问题,其实是和自环边 或 平行边是无关的。最典型的,如:要考察一张图的连通性,那么自环边和平行边都不会改变这张图的连通性。
——资料来源:图论简介 - 阿特曼
根据二分图的定义,那么对于图中任意两个节点 u 和 v,如果它们之间有一条边直接相连,那么 u 和 v 就必须属于不同的集合。
遍历无向图可以使用「深度优先搜索」或「广度优先搜索」。
使用「深度优先搜索」:
算法流程如下:
1.选节点 0 开始,将其染成红色(1),并从该节点开始对整个无向图进行遍历
2.调用 dfs,如果我们通过节点 i 遍历到了节点 j(即 i 和 j 在图中有一条边直接相连),如果 i 和 j 的颜色相同,则直接返回 false;如果 j 还未被染色( j 还为 0 的话),就递归调用dfs 以此对 j 的直接相连的节点进行遍历,后面不断回溯遍历该图
3.遍历结束,如果中途没有返回 false 则说明给定的无向图是二分图,返回 true 作为答案。
-下面代码(DFS版)
class Solution {
public:
bool dfs(vector>& graph, vector& cols, int i, int col) {
cols[i] = col;
for(int j : graph[i]) {
if (cols[j] == cols[i]) return false;
if (!cols[j] && !dfs(graph, cols, j, -col)) return false;
}
return true;
}
bool isBipartite(vector>& graph) {
int n = graph.size();
vector cols(n, 0);
for(int i = 0; i < n; i++) {
if (!cols[i] && !dfs(graph, cols, i, 1)) {
return false;
}
}
return true;
}
};
使用「广度优先搜索」:
如果给定的无向图连通,那么我们就可以任选一个节点开始,给它染成红色(设为1)。随后我们对整个图进行遍历,将该节点直接相连的所有节点染成绿色(设为-1),表示这些节点不能与起始节点属于同一个集合, 并将没有染色的( j 为 0 )相连的所有节点入队。随后 依次出队,再将这些绿色(设为-1)节点 直接相连没有染色的( j 为 0 )节点染成红色(设为1),以此类推,直到无向图中的每个节点均被染色。
因为题目给定的无向图不一定保证连通,因此我们需要进行多次遍历,直到每一个节点都被染色,或确定答案为 False 为止。
遍历结束,如果中途没有返回 false 则说明给定的无向图是二分图,返回 true 作为答案。
-下面代码(BFS版)
class Solution {
public:
bool isBipartite(vector>& graph) {
int n = graph.size();
vector cols(n, 0);
queue q;
for(int i = 0; i < n; i++) {
if (!cols[i]) {
q.push(i);
cols[i] = 1;
while (!q.empty()) {
int node = q.front();
q.pop();
for(int j : graph[node]) {
int temp = cols[node];
if (temp == cols[j]) return false;
if (!cols[j]) {
cols[j] = -temp;
q.push(j);
}
}
}
}
}
return true;
}
};