🌸题目
🍁给定一个无向图graph,当这个图为二分图时返回true。
如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。
graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1
之间的整数。这图中没有自环和平行边: graph[i]
中不存在i,并且graph[i]中没有重复的值。
1 | 示例 1: |
注意:
graph
的长度范围为 [1, 100]
。graph[i]
中的元素的范围为 [0, graph.length - 1]。
graph[i]
不会包含 i 或者有重复的值。
图是无向的: 如果j 在 graph[i]
里边, 那么 i 也会在 graph[j]里
边。
分析
对于图中的任意两个节点 u 和 v,如果它们之间有一条边直接相连,那么 u 和 vv必须属于不同的集合。
如果给定的无向图连通,那么我们就可以任选一个节点开始,给它分成第一组。随后我们对整个图进行遍历,将该节点直接相连的所有节点分成第二组,表示这些节点不能与起始节点属于同一个集合。我们再将这些第二组的节点直接相连的所有节点分成第一组,以此类推,直到无向图中的每个节点均被分组。
如果我们能够成功分组,那么一组和二组的节点各属于一个集合,这个无向图就是一个二分图;如果我们未能成功分组,即在分组的过程中,某一时刻访问到了一个已经分组的节点,并且它的组与我们将要给它分的组不相同,也就说明这个无向图不是一个二分图。
算法的流程如下:
我们任选一个节点开始,将其分组第一组,并从该节点开始对整个无向图进行遍历;
在遍历的过程中,如果我们通过节点 u 遍历到了节点 v(即 u 和 v 在图中有一条边直接相连),那么会有两种情况:
- 如果 v 未被分组,那么我们将其分成与 u 不同的组,并对 v 直接相连的节点进行遍历;
- 如果 v 被分组,并且组与 u 相同,那么说明给定的无向图不是二分图。我们可以直接退出遍历并返回 False 作为答案。
当遍历结束时,说明给定的无向图是二分图,返回 True 作为答案。
我们可以使用「深度优先搜索」或「广度优先搜索」对无向图进行遍历,下文分别给出了这两种搜索对应的代码。
注意:
题目中给定的无向图不一定保证连通,因此我们需要进行多次遍历,直到每一个节点都被分组,或确定答案为 False 为止。每次遍历开始时,我们任选一个未被分组的节点,将所有与该节点直接或间接相连的节点进行分组。
解法一:DFS
1 | //0 代表还未分组的数字,1代表分的是第一组,2代表分的是第二组 |
1 | class Solution: |
解法二: BFS
1 | public boolean isBipartite2(int[][] graph) { |
1 | class Solution: |