[路飞]_情侣牵手

149 阅读2分钟

「这是我参与2022首次更文挑战的第38天,活动详情查看:2022首次更文挑战

leetcode-765 情侣牵手

题目介绍

n 对情侣坐在连续排列的 2n 个座位上,想要牵到对方的手。

人和座位由一个整数数组 row 表示,其中 row[i] 是坐在第 i 个座位上的人的 ID。情侣们按顺序编号,第一对是 (0, 1),第二对是 (2, 3),以此类推,最后一对是 (2n-2, 2n-1)

返回 最少交换座位的次数,以便每对情侣可以并肩坐在一起。 每次交换可选择任意两人,让他们站起来交换座位。

示例1

输入: row = [0,2,1,3]
输出: 1
解释: 只需要交换row[1]和row[2]的位置即可。

示例2

输入: row = [3,2,0,1]
输出: 0
解释: 无需交换座位,所有的情侣都已经可以手牵手了。

提示:

  • 2n == row.length
  • 2 <= n <= 30
  • n 是偶数
  • 0 <= row[i] < 2n
  • row 中所有元素均无重复

解题思路

  1. 首先如果是 对情侣坐错位置,那么将他们换到正确的位置上需要 1
  2. 如果是 对情侣之间彼此坐错位置,那么将他们换到正确的位置上至少需要 2

演示文稿 4(6).gif

  1. 如果是 对情侣之间彼此坐错位置,那么将他们换到正确的位置上至少需要 3

演示文稿 4(7).gif

因此,如果有 n 对情侣彼此坐错位置的话,最少需要交换的次数为 n - 1

如果利用并查集来做的话,首先将情侣按对来编号,将彼此之间坐错位置的情侣连通起来,最后会得到 m 个集合,在这 m 个集合中,每个集合中的情侣只是和集合中的其他情侣坐错位置,和其他集合中的情侣没有关系,如果要将每个集合中的情侣正确拼对的话,需要的次数为 集合中的情侣对数 - 1,那么将 m 个集合中的情侣全部正确拼对的话,就需要 初始情侣对数 - 集合个数

解题代码

var minSwapsCouples = function(row) {
    // 计算情侣对数
    const n = row.length / 2
    const unionSet = new UnionSet(n)
    for (let i = 0; i < row.length; i += 2) {
        // 每队情侣的编号为 0: (0, 1), 1: (2, 3) …… i: (2i, 2i + 1)
        unionSet.merge(Math.floor(row[i] / 2), Math.floor(row[i + 1] / 2))
    }

    // 情侣对数 - 集合数
    return n - unionSet.getCount()
};

// 并查集
class UnionSet {
    constructor(n) {
        this.fa = []
        this.size = []
        // 初始时每队情侣为一个集合,有 n 个集合
        this.count = n
        for (let i = 0; i < n; i++) {
            this.fa[i] = i
            this.size[i] = 1
        }
    }

    get(v) {
        if (this.fa[v] === v) return v
        const root = this.get(this.fa[v])
        this.fa[v] = root
        return root
    }

    merge(a, b) {
        const ra = this.get(a), rb = this.get(b)
        if (ra === rb) return
        if (this.size[ra] < this.size[rb]) {
            this.fa[ra] = rb
            this.size[rb] += this.size[ra]
        } else {
            this.fa[rb] = ra
            this.size[ra] += this.size[rb]
        }
        // 每两个集合进行连通,则集合的数量少 1
        this.count--
    }

    // 获取集合数量
    getCount() {
        return this.count
    }
}