目录
1.题目
2.思路
主要在于理解二分图的概念。可以把节点分成两个集合X 和 Y, 集合内的节点没有直接相连的边,允许间接相连。图中所有的边,其实一个节点必然来源于X, 一个节点来源于Y。
需要注意的一点是,这个图可能并不是完全联通的。
这道题的思路可以把求两个独立的集合转化为给图中所有的点涂两种不同的颜色。
如果两个点有连接的边,那他们的颜色一定不同,假如出现矛盾的地方,那说明两种颜色满足不了,所以不满足二分图的性质,直接返回false.
- 用一个数组vis[]来记录图中节点的颜色。
- 如果vis[i] == 1, 说明给这个节点涂上了第一种颜色。(二分图中集合X)
- 如果vis[i] == -1, 说明给这个节点涂上了第二种颜色。(二分图中集合Y)
- 如果vis[i] == 0 ,说明是第一次访问,任意赋值一个颜色即可, 比如vis[i] = 1, 并且开始BFS。
- 由于图并不是完全联通,所以存在多个BFS的情况。注意剪枝。
- 剪枝:在BFS中,队列中存储节点的值,以及节点的flag.如果flag为1,代表染第一种颜色,也就是vis[i]必须为1,如果此时vis[i] = -1, 那么说明之前已经访问过并且染色了,说明出现矛盾,返回false。flag为-1的情况也类似。
时间复杂度——O(N + M)
N为图的节点个数。M为图的边数。因为存在剪枝的关系,所以每个边只会访问一次。节点只会访问一次。
空间复杂度——O(N)
队列存储,以及vis数组都是O(N)
class Solution {
public boolean isBipartite(int[][] graph) {
// 染色法
int n = graph.length;
int[]vis = new int[n];
Deque<int[]>d = new ArrayDeque();
for(int i = 0 ; i < n ; i++){
if(vis[i] == 0){
d.addLast(new int[]{i, 1});
while(!d.isEmpty()){
int[]temp = d.pollFirst();
int cur = temp[0], flag = temp[1];
if(flag == 1){
if(vis[cur] == 0 || vis[cur] == 1){
if(vis[cur] == 0)
vis[cur] = 1;
else
continue;
}
else
return false;
}
else{
if(vis[cur] == 0 || vis[cur] == -1){
if(vis[cur] == -1)
continue;
vis[cur] = -1;
}
else
return false;
}
int[]g = graph[cur];
for(int j : g){
d.addLast(new int[]{j, -flag});
}
}
}
}
return true;
}
}
3.结果