LeetCode 886
第一个想法是,就直接去归类,使用两个集合,根据关系把这些点放入集合,看看是否能分类成功。
def possibleBipartitionTimeout(self, N: int, dislikes: List[List[int]]) -> bool:
if len(dislikes) <= 1: return True
A = set()
B = set()
def canBipartition(dislikes, index, A, B) -> bool:
if index >= len(dislikes): return True
current = dislikes[index]
if (current[0] in A and current[1] in A) or (current[0] in B and current[1] in B):
return False
if current[0] in A:
B.add(current[1])
return canBipartition(dislikes, index + 1, A, B)
if current[1] in A:
B.add(current[0])
return canBipartition(dislikes, index + 1, A, B)
if current[0] in B:
A.add(current[1])
return canBipartition(dislikes, index + 1, A, B)
if current[1] in B:
A.add(current[0])
return canBipartition(dislikes, index + 1, A, B)
Ac = A.copy()
Bc = B.copy()
Ac.add(current[0])
Bc.add(current[1])
if (canBipartition(dislikes, index + 1, Ac, Bc)):
return True
A.add(current[1])
B.add(current[0])
return canBipartition(dislikes, index+1, A, B)
提交之后发现效率太低,超时了。
转换思路,改用在图里面找loop的方式,A不喜欢B,B不喜欢C,C不喜欢D,D不喜欢E,E不喜欢A。如果分成两类的话,在A的这边就会造成一个内部的循环。只要存在类似的loop,那么就是False。通过DFS的方式可以走遍整个图。但是图可能是不连通的,所有需要根据每个节点来做一次dfs。
def possibleBipartition(self, N: int, dislikes: List[List[int]]) -> bool:
if len(dislikes) <= 1: return True
graph = collections.defaultdict(list)
hasLoop = False
#-1表示还没有访问过
distance = [-1] * (N+1)
def dfs(start:int):
nonlocal hasLoop
if hasLoop: return
for neighbor in graph[start]:
#如果在自己一侧引起循环,设置hasLoop为True
if distance[neighbor] > 0 and (distance[neighbor] - distance[start]) % 2 == 0:
hasLoop = True
return
elif distance[neighbor] == -1:
distance[neighbor] = distance[start] + 1
dfs(neighbor)
for a, b in dislikes:
graph[a].append(b)
graph[b].append(a)
#遍历每个点进行DFS
for i in range(1, N):
if hasLoop: return False
#如果已经访问过,不需要重复访问
if distance[i] == -1:
distance[i] = 0
dfs(i)
return True