题目描述
N
对情侣坐在连续排列的 2N
个座位上,想要牵到对方的手。计算最少交换座位的次数,以便每对情侣可以并肩坐在一起 一次交换可选择任意两人,让他们站起来交换座位。
人和座位用 0
到 2N-1
的整数表示,情侣们按顺序编号,第一对是 (0, 1)
,第二对是 (2, 3)
,以此类推,最后一对是 (2N-2, 2N-1)
。
这些情侣的初始座位 row[i]
是由最初始坐在第 i
个座位上的人决定的。
样例
输入: row = [0, 2, 1, 3]
输出: 1
解释: 我们只需要交换 row[1] 和 row[2] 的位置即可。
输入: row = [3, 2, 0, 1]
输出: 0
解释: 无需交换座位,所有的情侣都已经可以手牵手了。
提示
len(row)
是偶数且数值在[4, 60]
范围内。- 可以保证
row
是序列0...len(row)-1
的一个全排列。
算法
(数论,贪心) $O(n)$
- 数组中相邻的两个数字一组,将数组分为
n/2
组。 - 每一组有可能已经是配对过的,也有可能是没配对的。如果是没配对的,则必定会与最多其它两个组产生关联。产生关联的含义是,这两组中分别含有一对情侣中的一个人。
- 通过简单的例子可以很容易的得知,这
n/2
个组,会形成若干个环。其中,每个环可以是单独一组(即已经配对好的);可以是两个组,即恰好这两个组包含了两对情侣;或三个或以上的组,组成一个多边形。 - 如果单独一组形成的环,则不需要任何改变;如果是两个组形成的环,则只需要这两个组之间交换一次;如果是三个或以上的组形成的,则我们可以发现,每次交换会使得环的长度减 1,当环的长度为 2 时,再需要一次交换就可以满足要求,故多个组的环需要的交换次数是环的大小减 1。
- 这里实现有个位运算的技巧,与
x
配对的情侣为x ^ 1
。
时间复杂度
- 每个位置最多被访问两次,故的时间复杂度为 $O(n)$。
空间复杂度
- 需要额外 $O(n)$ 的空间存储辅助的哈希表,以及记录每个位置是否被访问过。
C++ 代码
class Solution {
public:
int minSwapsCouples(vector<int>& row) {
unordered_map<int, int> h;
int n = row.size();
for (int i = 0; i < n; i++)
h[row[i]] = i >> 1;
vector<bool> vis(n >> 1, false);
int ans = 0;
for (int i = 0; i < (n >> 1); i++)
if (!vis[i]) {
int x = i;
while (1) {
vis[x] = true;
if (!vis[h[row[x << 1] ^ 1]])
x = h[row[x << 1] ^ 1];
else if (!vis[h[row[x << 1 | 1] ^ 1]])
x = h[row[x << 1 | 1] ^ 1];
else
break;
ans++;
}
}
return ans;
}
};
献上并查集与贪心
贪心