参考该博客大佬的讲解 置换环 - TTS-S - 博客园 (cnblogs.com)
置换环:一般用于解决数组排序元素间所需最小交换次数这类问题。
置换环思想:置换环是将每个元素指向其应在的位置,最终相连成一个环(若元素就在其应在的位置,则自身成环),因此可知元素的相互交换只会在该环内进行,所以可以得出每个环内所需的交换次数即为元素个数-1。将每个环所需的交换次数累加起来即为排序该数组所需的交换次数:数组长度-环的个数
。765. 情侣牵手 - 力扣(LeetCode)
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 解释: 无需交换座位,所有的情侣都已经可以手牵手了。
思路:我们需要将每对情侣都放在一块,编号 0 和 1 的人对应情侣 0,编号 2 和 3 的人对应情侣 1... 即编号为row[i]对应的情侣编号为row[i]/2(c++向下取整)。如果有k对情侣相互之间坐错了位置,即k对情侣处于一个置换环中,那么他们之间需要经过 k−1 次交换才能都坐到正确的位置上。所以,我们通过一次遍历,通过并查集找出共有多少个置换环,交换次数就等于数组个数-环的个数,即n - x 为所求答案。(此题中我们将情侣对数作为数组个数,所以n为n/2)
class Solution { public: int minSwapsCouples(vector<int>& row) { int n = row.size() / 2; int p[n]; iota(p, p + n, 0); function<int(int)> find = [&](int x) -> int { if(p[x] != x) p[x] = find(p[x]); return p[x]; }; for(int i = 0; i < n << 1; i += 2) { int a = row[i] >> 1, b = row[i + 1] >> 1; p[find(a)] = find(b); } int res = n; for(int i = 0; i < n; i ++ ) res -= i == find(i); return res; } };