leetcode--785. Is Graph Bipartite?
問題
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
}
遇到的問題
最初程式碼並沒有考慮圖不連通的情況,所以對於多聯通分量並不能通過測試: