这是一个经典的换座位问题,可以很好地利用并查集解决。如果有N对情侣彼此纠缠,那么共需要交换N-1次。知道这个定律后,咱们只需用并查集统计出有几个团即可。注:并查集的按秩合并和路径压缩是很好地技巧,咱们再在并查集内部加一个父亲节点统计儿子数量的字典即可。
from collections import defaultdict
class Solution:
def minSwapsCouples(self, row: List[int]) -> int:
class Unionfind:
def __init__(self, n):
self.father = [-1 for _ in range(n)]
self.rank = [0 for _ in range(n)]
self.father2childnum = defaultdict(int)
def union(self, a, b):
r1, r2 = self.find(a), self.find(b)
if r1 == r2: return
if self.rank[r1] <= self.rank[r2]:
self.rank[r1] = max(self.rank[r2]+1, self.rank[r1])
self.father[r1] = r2
self.father2childnum[r2] += self.father2childnum[r1]+1
del self.father2childnum[r1]
else:
self.rank[r2] = max(self.rank[r1]+1, self.rank[r2])
self.father[r2] = r1
self.father2childnum[r1] += self.father2childnum[r2]+1
del self.father2childnum[r2]
def find(self, a):
l = []
while self.father[a] >= 0:
l.append(a)
a = self.father[a]
for num in l:
self.father[num] = a
return a
u = Unionfind(len(row))
for i in range(len(row)):
if row[i] & 1:
row[i] -= 1
for i in range(0, len(row), 2):
u.union(row[i], row[i+1])
ret = 0
for father in u.father2childnum:
ret += u.father2childnum[father]
return ret