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.
Note:
graph
will have length in range[1, 100]
.graph[i]
will contain integers in range[0, graph.length - 1]
.graph[i]
will not containi
orduplicate
values.- The
graph
is undirected: if any elementj
is ingraph[i]
, theni
will be ingraph[j]
.
Difficulty: medium
785. Is Graph Bipartite?
中文描述
给定一个图,问这个图是否是个二部图?
二部图的定义是,把图中的节点分成独立的两部分集合,记为A
和B
(不存在交集),然后保证图中的所有边都的两个顶点,一个属于A
,另一个属于B
。
输入格式
输入一个列表graph
,列表的第i
个元素graph[i]
表示的是第i
个节点相连接的节点的集合。例如graph
是[[1,3], [0,2], [1,3], [0,2]]
,表示第0
个节点和第1
和3
个节点相连,第1
个节点和第0
和2
个节点相连,以此类推。
Examples:
Input: [[1,3], [0,2], [1,3], [0,2]]
Output: true
解释:
这个图看起来是这样:
0——1
|·······|
|·······|
3——2
我们可以把它分为两个部分: {0, 2} 和 {1, 3}.Input: [[1,2,3], [0,2], [0,1,3], [0,2]]
Output: false
这个图看起来是这样:
0——1
| ··\··· |
| ···\·· |
3——2
我们无法将其分成两个部分
解答思路
考虑从第i
个节点开始考虑,如果该节点i
还没被放入A
或则B
中,则考虑把其放入A
中,并且把i
标记为已用。之后与i
相连的节点只能放到B
中,如果与i
相连的节点有存在于A
中的,则已经不满足条件,可以返回False
。否则就对与i
相连的节点重复上述操作,不过这次与这些节点相连的只能放到B
中,如果有在A
中的则返回False
。这样在A
和B
之间交替,直到没有未用过的节点为止。这样所有与节点i
有直接或则间接联系的节点就被遍历完了。我们就可以考虑下一个与节点i
无关的节点。
代码
class Solution(object):
def isBipartite(self, graph):
"""
:type graph: List[List[int]]
:rtype: bool
514ms
"""
# 用来存放两边的节点
subsets_A = set()
subsets_B = set()
# 用来存放用过的节点
used = set()
# 从0号节点开始考虑
for i in range(len(graph)):
if i not in used:
# 没使用过的节点放到A中
subsets_A.add(i)
# 当前的节点集合
cur_list = [i]
# 用来记录是放在A还是B
count = 0
while cur_list:
next_list = []
# 对所有与第i个节点相连的节点都只能放到对面
for j in cur_list:
used.add(j)
for opposite in graph[j]:
# 当前节点都是A中的,与之相连的只能放到B里,如果有在A里的就无法满足题目要求
if count % 2 == 0:
if opposite in subsets_A:
return False
subsets_B.add(opposite)
# 当前节点都是B中的,与之相连的只能放到A里,如果有在B里的就无法满足题目要求
else:
if opposite in subsets_B:
return False
subsets_A.add(opposite)
# 只记录没被使用过的节点
if opposite not in used:
next_list.append(opposite)
# 当前节点变化,从A->B或则从B->A
count += 1
cur_list = next_list
return True
写的很菜,速度也慢= =,附上其它人写的dfs的代码详细请见Python 7 lines DFS graph coloring w/ graph and Explanation:
class Solution(object):
def isBipartite(self, graph):
"""
:type graph: List[List[int]]
:rtype: bool
57ms
"""
def dfs(v, cur_color):
# 如果v再次出现,则判断是不是是在同一边,不是同一边返回False
if v in color:
return color[v] == cur_color
# 否则记录v的分在哪边
color[v] = cur_color
# cur_color ^ 1 用来转化A->B,或则B->A
return all(dfs(w, cur_color ^ 1) for w in graph[v])
color = {}
# 如果iterable的所有元素不为0、''、False或者iterable为空,all(iterable)返回True,否则返回False;
return all(dfs(v, 0) for v in range(len(graph)) if v not in color)