题目描述
分析
题目给一个数组代表一行人,这个数组里是一堆编号,从零开始每两个相邻的人是情侣,那么题目肯定不会是从零开始一直单调递增,所以肯定是要我们通过两两交换的方式,最终去让所有的情侣都在一起,所以现在要找的就是怎么统计交换的数量
算法
并查集
解题思路
通过题目描述,进行观察可知:
对于两对情侣,最多需要交换一次;
对于三对情侣,最多需要交换两次
因此,可以通过并查集区连接情侣们,这里连接的是每一对情侣,因此 DSU 中存储的是这对情侣的联通情况,而这个 root 是情侣的编号,这个编号是偶数,也就是从0开始每对情侣的偶数编号位置
由上面的结论,可以两两遍历数组,连接这两个元素,然后检查 DSU 中存储的情侣有多少不以自己为 root
代码
function minSwapsCouples(row) {
const len = row.length
const N = len >> 1
const u = new DSU(N)
for (let i = 0; i < len; i += 2) {
u.merge(row[i] >> 1, row[i + 1] >> 1)
}
let cnt = 0
for (let i = 0; i < N; i++) {
if (u.get(i) !== i) cnt++
}
return cnt
}
class DSU {
constructor(n) {
this.fa = new Array(n).fill(0).map((v, i) => i)
}
get(x) {
return this.fa[x] === x ? x : this.get(this.fa[x])
}
merge(a, b) {
this.fa[this.get(a)] = this.get(b)
}
}