给定一个无向图graph
,当这个图为二分图时返回true
。
如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。
graph
将会以邻接表方式给出,graph[i]
表示图中与节点i
相连的所有节点。每个节点都是一个在0
到graph.length-1
之间的整数。这图中没有自环和平行边: graph[i]
中不存在i
,并且graph[i]
中没有重复的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 示例 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 我们不能将节点分割成两个独立的子集。
|
注意:
graph
的长度范围为 [1, 100]
。
graph[i]
中的元素的范围为 [0, graph.length - 1]
。
graph[i]
不会包含 i
或者有重复的值。
- 图是无向的: 如果
j
在 graph[i]
里边, 那么 i
也会在 graph[j]
里边。
对于图中任意两个结点 u 和 v ,如果它们之间有一条边相连,那么 u 和 v 必须属于不同的集合。
如果给定的无向图连通,那么我们就可以任选一个结点开始,给它染成红色,将其所连的所有结点染成绿色,同一种颜色表示它们在同一个集合里,我们再将绿色结点直接相连的未染色结点染成红色。
算法流程:
任选一个结点开始,将其染成红色,并从该结点开始对整个无向图进行遍历;
在遍历过程中,如果我们通过结点 u 访问到了结点 v (u,v之间有一条边相连),那么会有两种情况:
- 如果 v 未染色,将其染成与 u 不同的颜色,并对 v 直接相连的结点进行遍历;
- 如果 v 被染色,并且颜色与 u 相同,说明给定的无向图不是二分图,我们直接返回 false;
当遍历结束时,说明给定的无向图是二分图,返回 true。
我们可以使用「深度优先搜索」或「广度优先搜索」对无向图进行遍历。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class Solution { private static final int UNCOLORED = 0; private static final int RED = 1; private static final int GREEN = 2; private int[] color; private boolean valid;
public boolean isBipartite(int[][] graph) { int n = graph.length; color = new int[n]; valid = true; Arrays.fill(color, UNCOLORED); for(int i = 0; i < n; i++){ if(color[i] == UNCOLORED){ dfs(i, RED, graph); } } return valid; }
public void dfs(int node, int c, int[][] graph){ color[node] = c; int cNei = c == RED ? GREEN : RED; for(int neighbor : graph[node]){ if(color[neighbor] == UNCOLORED){ dfs(neighbor, cNei, graph); if(!valid){ return; } }else if(color[neighbor] != cNei){ valid = false; return; } } } }
|
下面是 BFS 实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Solution { private static final int UNCOLORED = 0; private static final int RED = 1; private static final int GREEN = 2; private int[] color;
public boolean isBipartite(int[][] graph) { int n = graph.length; color = new int[n]; Arrays.fill(color, UNCOLORED);
for(int i = 0; i < n; i++){ if(color[i] == UNCOLORED){ Queue<Integer> queue = new LinkedList<>(); queue.offer(i); color[i] = RED; while(!queue.isEmpty()){ int node = queue.poll(); int cNei = color[node] == RED ? GREEN : RED; for(int neighbor : graph[node]){ if(color[neighbor] == UNCOLORED){ queue.offer(neighbor); color[neighbor] = cNei; }else if(color[neighbor] != cNei){ return false; } } } } } return true; } }
|
时间复杂度O(N + M),其中 N 和 M 分别是无向图的点数和边数。
空间复杂度O(N),存储结点颜色数组需要 O(N)空间。