N 对情侣坐在连续排列的 2N 个座位上,想要牵到对方的手。 计算最少交换座位的次数,以便每对情侣可以并肩坐在一起。 一次交换可选择任意两人,让他们站起来交换座位。
人和座位用 0 到 2N-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
解释: 无需交换座位,所有的情侣都已经可以手牵手了。
说明:
len(row)是偶数且数值在[4, 60]范围内。- 可以保证
row是序列0...len(row)-1的一个全排列。
解题思路
1.遍历row数组,每次都去取出来两个人,我们知道正常的情侣他的编号从0开始
2.一对正确的情侣就是一个是偶数一个是奇数;
并且奇数= 偶数+1;和奇数/2 == 偶数/2;这个时候才是情侣;否则就需要将两个
编号除以2之后的结果进行连通,进行交换次数;
3.当N-1对配对成功的时候,最后一对也会配对成功;我们只需要记录连通合并的次数就是
可以调整的次数;
图解
代码实现
/*
1.遍历row数组,每次都去取出来两个人,我们知道正常的情侣他的编号从0开始
2.一对正确的情侣就是一个是偶数一个是奇数;
并且奇数= 偶数+1;和奇数/2 == 偶数/2;这个时候才是情侣;否则就需要将两个
编号除以2之后的结果进行连通,进行交换次数;
3.当N-1对配对成功的时候,最后一对也会配对成功;我们只需要记录连通合并的次数就是
可以调整的次数;
*/
var minSwapsCouples = function(row) {
let len = row.length;
let N = len >> 1; //右移1位 相等于除以2
let uf = new UnionFind(N);
for(let i = 0; i < len; i+=2){//跳着循环,每次取2个值
uf.unite(row[i] >> 1,row[i+1] >> 1);//拿到这两个人之后都给他除以2,进行连通
}
return N - uf.getCount();//情侣的长度,减去并查集里面的连通分量
};
class UnionFind{
constructor(n){
this.parent = new Array(n).fill(0).map((val,index)=>index);
this.rank = new Array(n).fill(0);
this.setCount = n;
}
findSet(index){
if(this.parent[index] != index){
this.parent[index] = this.findSet(this.parent[index])
}
return this.parent[index];
}
unite(index1,index2){
let root1 = this.findSet(index1);
let root2 = this.findSet(index2);
if(root1 != root2){
if(root1 < root2){
[root1,root2] = [root2,root1];
}
this.parent[root2] = root1;
this.rank[root1] += this.rank[root2];
this.setCount--;
}
}
getCount(){
return this.setCount;
}
connected(index1,index2){
let root1 = this.findSet(index1),root2 = this.findSet(index2);
return root1 == root2
}
}
至此我们就完成了leetcode-765-情侣牵手
欢迎小伙伴们建议讨论~~