
- 首先不考虑已经正确坐在一起的组合
- 在没有坐在一起的组合中,只有当两对情侣互相配对时只需要一次交换操作就可以使得两对情侣完成匹配,其余情况交换数等于情侣对数
- 可以把所有情侣看成一个大集合,这个大集合是可以拆成若干小集合的,比如对于排列0471652983,显然前六个047165之间的交换仅发生在前六个之中与后四个无关,按照这样的规则,我们可以把整个集合分割成(不存在正确匹配,内部可完成交换,不可再分割)的若干小集合
- 现在问题转化为求解 3 中描述的小集合的最少交换次数,对于这样的集合只有在最后一次交换的时候才会发生在第二步中描述的第一种情况,因为如果在最后一次交换前发生了这种情况,假设是第 k 次交换是两两匹配的,那么在第 k 次交换前的所有情侣的组合就可以构成一个更小的组合,不满足我们一开始的假设
- 总结,如果 ij 靠在一起那么那他们必定是同一个小集合的,通过将 i 节点与 j 节点连接的方式来表示它们属于一个集合,最终我们会的到一张非连通图,答案就是每一个连通分量的大小 -1 的和
class Solution:
def minSwapsCouples(self, row: List[int]) -> int:
near = defaultdict(list)
vis = set()
for i in range(0, len(row), 2):
if row[i] // 2 == row[i + 1] // 2:
vis.add(row[i] // 2)
continue
near[row[i] // 2].append(row[i + 1] // 2)
near[row[i + 1] // 2].append(row[i] // 2)
ans = 0
for i in range(len(row) // 2):
if i in vis:
continue
t = [i]
while len(t) > 0:
for _ in range(len(t)):
k = t.pop()
if k in vis:
continue
vis.add(k)
t.extend(near[k])
ans += 1
ans -= 1
return ans