[路飞]_前端算法第九十四弹-情侣牵手

150 阅读2分钟

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

人和座位用 02N-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
解释: 无需交换座位,所有的情侣都已经可以手牵手了。

这道题我第一想法是使用map函数

  • 将row中所有数都存入map,记录下标。

  • 遍历row,判断同座位两个数是否符合。

  • 不符合变找到符合的数,与当前数替换,在map中也替换。

  • 同时记录替换的次数。

    var minSwapsCouples = function (row) { let num = 0; let len = row.length let u = new UnionSet(len) let map = new Map() // 将下标存入map中 for (let i = 0; i < len; i++) { map.set(row[i], i) } // 按双数遍历 for (let i = 0; i < row.length; i = i + 2) { // 判断座位号 if (row[i] % 2 == 0) { // 判断是否是情侣 if (row[i] + 1 != row[i + 1]) { // 不是就去找对应的情侣,换座 let j = map.get(row[i] + 1); [row[i + 1], row[j]] = [row[j], row[i + 1]]; // 重新记录座位号 map.set(row[i + 1], i + 1) map.set(row[j], j) // HR尊次数加一 num++; } } else { // 理论同上 if (row[i + 1] != row[i] - 1) { let j = map.get(row[i] - 1); [row[i + 1], row[j]] = [row[j], row[i + 1]] map.set(row[i + 1], i + 1) map.set(row[j], j) num++; } } } console.log(num); return num > 0 ? num - 1 : num };

let j = map.get(row[i] + 1);必须加;,否则下面的交换会报错

但是这种方法在力扣上耗时非常严重,后来想到了用并查集的方法,将能组成情侣的组合看做一个并查集。

比如**[1,4,0,5,8,7,6,3,2,9][1,4,0,5]**就可以看做是一个并查集,因为经过交换,能组成情侣。**[8,7,6,3,2,9]**看做成一个并查集。我们查看一共有多少组情侣,多少个并查集,想减就是需要交换的次数。

var minSwapsCouples = function (row) {
	// 人数
  const len = row.length、
	// 情侣数
  const n = len / 2
  const u = new UnionSet(n)
	// 创建并查集
  for (let i = 0; i < len; i += 2) {
    const l = Math.floor(row[i] / 2)
    const r = Math.floor(row[i + 1] / 2)
    u.merge(l, r)
  }
	// 查看并查集数
  let cnt = 0
  for (let i = 0; i < n; i++) {
    if (u.get(i) == i) cnt++
  }
 return n-cnt
};
class UnionSet {
  constructor(n) {
    this.fa = new Array(n + 1)
    this.n = n
    this.cnt = new Array(n + 1)
    for (let i = 0; i < n; i++) {
      this.fa[i] = i
      this.cnt[i] = 1
    }
  }
  get (x) {
    return this.fa[x] = (this.fa[x] == x ? x : this.get(this.fa[x]))
  }
  merge (a, b) {
    if (this.get(a) == this.get(b)) return
    this.cnt[this.get(b)] += this.cnt[this.get(a)]
    this.fa[this.get(a)] = this.get(b)
    return
  }
}