题目描述:
n
对情侣坐在连续排列的2n
个座位上,想要牵到对方的手。人和座位由一个整数数组
row
表示,其中row[i]
是坐在第i
个座位上的人的 ID。情侣们按顺序编号,第一对是(0, 1)
,第二对是(2, 3)
,以此类推,最后一对是(2n-2, 2n-1)
。返回 最少交换座位的次数,以便每对情侣可以并肩坐在一起。 每次交换可选择任意两人,让他们站起来交换座位
我们可以给每一对情侣编号,编号为 idx
的人对应的 “情侣编号” 为 idx / 2
;
如果有 k
对情侣相互之间坐错了位置,也就是说,这 k
对情侣仅通过互相之间交换位置就能够满足牵手,那么他们之间需要且仅需要经过 k−1
次交换来坐到正确的位置上。这样的 k
对情侣形成了一个 “环”。
为什么?不妨这样考虑,我们先调整一对情侣的位置,使其坐到正确的位置上,那么问题就从 k
对情侣的问题,转换成了 k−1
对情侣的问题。依此类推,最终 k=1
时,交换次数为 0
。所以,如果 k
对情侣相互之间坐错了位置,那么需要 k−1
次交换。
因此,我们只需要遍历一遍数组,利用并查集找出有多少个环。假设有 x
个,每个环中分别有 对情侣,那么答案就是 。
class Solution {
private int[] fa;
private int find(int x) {
if(fa[x] != x) {
fa[x] = find(fa[x]);
}
return fa[x];
}
public int minSwapsCouples(int[] row) {
// 共 n 对情侣
int n = row.length >> 1;
fa = new int[n];
for(int i = 0; i < n; i++) fa[i] = i;
// 把相邻的两个人放到一个并查集中
for(int i = 0; i < n << 1; i += 2) {
int a = row[i] >> 1, b = row[i + 1] >> 1;
fa[find(a)] = find(b);
}
int ans = n;
// 每有一个集合/环,答案减一
for(int i = 0; i < n; i++) {
if(i == fa[i]) ans--;
}
return ans;
}
}