持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情
题目描述
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 解释: 无需交换座位,所有的情侣都已经可以手牵手了。
并查集
思路分析:很明显看出来这是一个并查集的模板题,大致思路:所有人一共分为 n / 2 对情侣,对所有人进行遍历,判断当前组的两个人是不是已经是情侣,那么不需要和其他人进行交换,不然放到圈子里面去找情侣。答题就是找环解环的过程。
核心:每两个座位成一对,假定左边的人都是合法的不变,如果TA右边的人与TA匹配则跳过,不匹配则找到TA的匹配对象的与TA右边的人交换。
具体实现步骤注意点:
因为每对情侣是两个人,那么只需要遍历n/2次
所有的情侣之间的关系为n,n+1或n,n-1
因此在遍历过程中只需要判断当前row[i]和row[i+1]是否符合情侣关系
由于是任意交换,有不符合规则的只需交换一次即可,每次交换对count进行+1
class Solution {
public int minSwapsCouples(int[] row) {
int n = row.length/2;
Union u = new Union(n);
for(int i = 0; i < n; i++){
u.connect(row[i*2]/2,row[i*2+1]/2);
}
return u.getPart();
}
class Union{
int[] parent;
int[] sizes;
int total;
public Union(int n){
parent = new int[n];
for(int i = 0; i < n; i++){
parent[i] = i;
}
sizes = new int[n];
Arrays.fill(sizes,1);
total = n;
}
public int getPart(){
return sizes.length-total;
}
public void connect(int a, int b){
int rootA = root(a);
int rootB = root(b);
if(rootA==rootB) return;
if(sizes[rootA]>=sizes[rootB]){
sizes[rootA]+=sizes[rootB];
parent[rootB] = rootA;
}else{
sizes[rootB]+=sizes[rootA];
parent[rootA] = rootB;
}
--total;
}
private int root(int a){
while(parent[a]!=a){
parent[a] = root(parent[a]);
a = parent[a];
}
return a;
}
}
}
最后
作为单身狗,做这个题目稍有不适。难受,做完就烧了他们