https://leetcode-cn.com/problems/is-graph-bipartite/
动态维护A、B集合算法
class Solution(object):
def isBipartite(self, graph):
"""
:type graph: List[List[int]]
:rtype: bool
"""
# 由于每一条边的两个节点要来自不同的子集
# 那么设节点1属于集合A,节点1邻接的节点应当属于集合B
# 维护集合A、集合B。遍历图的节点并更新两个集合
# 一旦检测到某个节点与其邻接的节点属于同一集合,则返回False
# 我们应该遍历完所有节点,但是需要根据邻接关系先遍历一整块连在一起的节点
# 因此维护一个队列和记录没有遍历过的节点的备忘录
n = len(graph)
A = set()
B = set()
queue = collections.deque([0])
memo = set(range(n))
while queue:
i = queue.popleft()
relation = set(graph[i])
if i in A:
# 自己的邻接节点与自己所处集合有交集
if relation & A:
return False
# 将自己的邻接节点放到另一个集合中
B |= relation
elif i in B:
if relation & B:
return False
A |= relation
else:
# 当某个节点不属于任何一个集合时,有两种情况
# 1.这是第一个节点
# 2.此节点与此前其他节点不邻接
# 这两种情况,都是可以将这个节点随意分配到一个集合中而不影响结果的
A.add(i)
B |= relation
# 将其邻接节点入队列
for j in graph[i]:
if j in memo:
queue.append(j)
# 即将遍历的节点从备忘录中删除
memo.remove(j)
# 当队列遍历完但memo不为空时,说明还有一块节点没有遍历
# 因此从memo中随机取一个节点加入队列
if not queue and memo:
queue.append(memo.pop())
return True