N 对情侣坐在连续排列的 2N 个座位上,想要牵到对方的手。 计算最少交换座位的次数,以便每对情侣可以并肩坐在一起。 一次交换可选择任意两人,让他们站起来交换座位。

人和座位用 0 到 2N-1 的整数表示,情侣们按顺序编号,第一对是 (0, 1),第二对是 (2, 3),以此类推,最后一对是 (2N-2, 2N-1)。

这些情侣的初始座位  row[i] 是由最初始坐在第 i 个座位上的人决定的。

示例 1:

输入: row = [0, 2, 1, 3]

输出: 1

解释: 我们只需要交换row[1]和row[2]的位置即可。

示例 2:

输入: row = [3, 2, 0, 1]

输出: 0

解释: 无需交换座位,所有的情侣都已经可以手牵手了。

说明:

len(row) 是偶数且数值在 [4, 60]范围内。

可以保证row 是序列 0...len(row)-1 的一个全排列。

通过次数24,470提交次数36,609

参考了官方并查集思路画了点图,希望好理解一点,如果有不对的地方,麻烦各位大佬指正

题意最后要实现的结果是,传入一个数组,数组长度为2N,数组内的元素之间要完成(2i-2, 2i-1)的配对组合,i的范围是[0,N - 1],问需要交换几次能完成配对

假设传入数组[0,2,1,4,5,3],将每组情侣视为一组,可以看成[[0,2],[1,4],[5,3]]视为3个组,那么每个位置对应的情侣组就是[[0,1],[0,2],[2,1]],这样通过这个结果可以连接情侣组之间的关系

就可以生成如下的图,代表0,1,2这3个情侣组之间产生了环,拆开这个环,让每个组的parent属性都等于本身,就可以得到之后的结果

交换第一次[0,0,1,2,2,1] 拆开了[0,1],[0,2]

交换第二次[0,0,1,1,2,2]完成交换,每两两座位中的是一对,根据交换完后的数组连通的图就如下图所示,即每个情侣的parent属性都是自己,就完成了最后交换

但是这道题不需要求交换的结果,最后返回的就是当前节点.parent != 当前节点的个数

所以最后的计算方法是:

根据有多少节点创建对应N数量的情侣组节点

遍历整个传入的数组,计算两两之间是否是同一组

如果不是同一组,就将两个元素对应的组连接起来

遍历连接后的nodes,计算结果

代码

/**
* @param {number[]} row
* @return {number}
*/

class UnionFind {
constructor(n) {
this.parent = []
this.count = n
for(let i = 0; i < n; i++) {
this.parent[i] = i
}
}
find(p) {
while(p !== this.parent[p]) {
this.parent[p] = this.parent[this.parent[p]]
p = this.parent[p]
}
return p
}
marge(p, q) {
let parentP = this.find(p);
let parentQ = this.find(q);console.log('***')
if (parentP !== parentQ) {
this.parent[parentP] = parentQ
console.log('***')
this.count--
}
}

}
var minSwapsCouples = function(row) {
let n = row.length
let num = n / 2
let unionfind = new UnionFind(num)
console.log(unionfind)
for(let i = 0; i < n; i += 2) {
let l = Math.floor(row[i]/2)
let r = Math.floor(row[i+1]/2)
// if (l === r) continue
unionfind.marge(l,r);
}
return num - unionfind.count
};