765. 情侣牵手

212 阅读1分钟

题目描述

leetcode-cn.com/problems/co…

分析

题目给一个数组代表一行人,这个数组里是一堆编号,从零开始每两个相邻的人是情侣,那么题目肯定不会是从零开始一直单调递增,所以肯定是要我们通过两两交换的方式,最终去让所有的情侣都在一起,所以现在要找的就是怎么统计交换的数量

算法

并查集

解题思路

通过题目描述,进行观察可知:

对于两对情侣,最多需要交换一次;
对于三对情侣,最多需要交换两次

因此,可以通过并查集区连接情侣们,这里连接的是每一对情侣,因此 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)
  }
}