问题
Given an undirected graph, return true if and only if it is bipartite.
Recall that a graph is bipartite if we can split it’s set of nodes into two independent subsets A and B such that every edge in the graph has one node in A and another node in B.
The graph is given in the following form: graph[i] is a list of indexes j for which the edge between nodes i and j exists. Each node is an integer between 0 and graph.length - 1. There are no self edges or parallel edges: graph[i] does not contain i, and it doesn’t contain any element twice.
Example 1:
Input: [[1,3], [0,2], [1,3], [0,2]]
Output: true
Explanation:
The graph looks like this:
0----1
| |
| |
3----2
We can divide the vertices into two groups: {0, 2} and {1, 3}.
Example 2:
Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
Output: false
Explanation:
The graph looks like this:
0----1
| \ |
| \ |
3----2
We cannot find a way to divide the set of nodes into two independent subsets.
Note:
- graph will have length in range [1, 100].
- graph[i] will contain integers in range [0, graph.length - 1].
- graph[i] will not contain i or duplicate values.
- The graph is undirected: if any element j is in graph[i], then i will be in graph[j].
思路与解法
题意比较简单:即判断输入的图是否可以划分为二部图。首先了解一下什么是二部图:
二部图也称作二分图,假设G=(V,E)
是一个无向图,如果定点V
可分割为两个互不相交的子集(A,B)
,并且图中的每条边(i,j)
所关联的两个定点i
和j
分别属于这两个不同的顶点集(i in A, j in B)
,则称图G
为一个二分图。
图示如下:
上图中所有点分为两个集合,且每个集合中的节点之间并没有边相连。所以是一个二部图。
思路与想法如下:
对于一棵树,若可以划分为二部图,则该树的奇数深度层的节点必定位于同一集合A
,同样的,所有偶数深度层的节点位于另一集合B
,并且,每个集合中必定不存在有边相连的两个点。如下图所示:该树可划分为{A,D,E,F}
和{B,C,G,H,I,J}
两个集合。
所以,对于图,我们也可以采用树的思想,至于如何进行集合的划分,我们可以对节点进行染色处理。从根节点开始,将根节点(深度为1)染色为Red
,然后进行BFS
遍历,和根节点直接相连的节点(深度为2)染色为Blue
。然后与这些节点相连的节点(深度为1、2或3),便存在两种不同的情况:未染色的点和已染色的点;对于未染色的点(深度为3)我们将其染色为Red
即可,但对于已染色的点,若该节点的颜色为Blue
(深度为2),则说明该节点根节点相连,即深度为2的节点中存在直接相连的两个点,则该图不能划分为二部图程序终止即可;若该节点的颜色为Red
,则表明该节点即为根节点(深度为1),不进行任何操作,可以继续正常遍历。在整个计算过程中,若程序没有中途退出,则表明该图可以划分为二部图。简单来说:
在染色的过程中,对于节点V
(已染色),若与其相连的节点U
为染色,则将U
染色为异色即可;若U已染色且其颜色与V
不同,则不需要进行操作;若U
已染色且颜色与V
相同,则提前终止程序。
代码实现
此算法我才用go语言实现:
func isBipartite(graph [][]int) bool {
// Graph 存储图、Color存储染色状态
Graph := make(map[int][]int)
var Color [150]int
for index, _ := range Color { // 初始化Color
Color[index] = -1
}
for node, edges := range graph {
Graph[node] = edges
}
// 最外层循环:输入数据可能存在多个联通分量的情况,即图可能并不连通;所以需要处理每个联通分量
for index, _ :=range Color {
// 以未染色的第一个节点为根节点开始BFS
if Color[index] == -1 {
// 利用队列模拟BFS
queue := make([]int, 0)
queue = append(queue, index)
head := 0
// 0,1代表Red和Blue
Color[index] = 0
for head < len(queue) {
// 遍历与queue[head]相连的所有节点并进行判断
for _, edge := range Graph[queue[head]] {
if Color[edge] == -1 {
Color[edge] = 1 - Color[queue[head]]
queue = append(queue, edge)
} else if Color[edge] == Color[queue[head]] {
return false
}
}
head++
}
}
}
return true
}
遇到的问题
最初代码并没有考虑图不连通的情况,所以对于多联通分量并不能通过测试: