LeetCode 765. 情侣牵手(并查集/贪心)

在这里插入图片描述

思路:
(完全是被题目名字吸引)
每个人编号为 r o w [ i ] row[i] row[i],那么其对应组号就为 r o w [ i ] / 2 row[i]/2 row[i]/2,这保证 x , x ⊕ 1 x,x⊕1 x,x1在同一组。
然后我们将相邻两个位置数对应组号连边,也就是 r o w [ i ] − > r o w [ i + 1 ] , i 为 奇 数 row[i]->row[i+1],i为奇数 row[i]>row[i+1]i,用并查集维护。这样的话得出一个 k k k元环就只需要 k − 1 k-1 k1次操作,那么只需要看并查集最后形成几个连通块就好了。

贪心解法的话,就是每次考虑当前数,然后将其同组的移过来,也就是每次修复一组。原理的话和上面一样,假设 k k k元环,交换一次拆成了两个环,操作次数加起来还是没变,所以每次至少贪心的满足一组配对就好了。

并查集解法,算出其中有多少个环

class Solution {
public:int fa[105];int findset(int x) {if(fa[x] == x) return x;return fa[x] = findset(fa[x]);}void Union(int x,int y) {x = findset(x),y = findset(y);if(x != y) {fa[x] = y;}}int minSwapsCouples(vector<int>& row) {int n = row.size(),m = n / 2;int ans = m;for(int i = 0;i < m;i++) fa[i] = i;    for(int i = 0;i < n;i += 2) {Union(row[i] / 2,row[i + 1] / 2);}for(int i = 0;i < m;i++) {if(i == findset(i)) ans--;}return ans;}
};

贪心解法,每次交换使得至少一个满足配对

class Solution {
public:int minSwapsCouples(vector<int>& row) {int n = row.size();vector<int>cache(n);for(int i = 0;i < n;i++) {cache[row[i]] = i;}int ans = 0;for(int i = 0;i < n;i += 2) {int b = row[i] ^ 1;if(row[i + 1] != b) {cache[row[i + 1]] = cache[b];swap(row[i + 1],row[cache[b]]);ans++;}}return ans;}
};