太过分了,2月14这样杀狗??
LeetCode上情侣牵手,被题目气死,不想多说,参考官方题解,直接并查集搞定他
题意最后要实现的结果是,传入一个数组,数组长度为2N,数组内的元素之间要完成(2i-2, 2i-1)的配对组合,i的范围是[0,N - 1],问需要交换几次能完成配对
这里用到并查集的解法
假设传入数组[0,2,1,4,5,3],将每组情侣视为一组,可以看成[[0,2],[1,4],[5,3]]视为3个组,那么每个位置对应的情侣组就是[[0,1],[0,2],[2,1]],这样通过这个结果可以连接情侣组之间的关系
就可以生成如下的图,代表0,1,2这3个情侣组之间产生了环,拆开这个环,让每个组的
parent
属性都等于本身,就可以得到之后的结果交换第一次[0,0,1,2,2,1] 拆开了[0,1],[0,2]
交换第二次[0,0,1,1,2,2]完成交换,每两两座位中的是一对,根据交换完后的数组连通的图就如下图所示,即每个情侣的parent属性都是自己,就完成了最后交换
但是这道题不需要求交换的结果,最后返回的就是
当前节点.parent != 当前节点
的个数所以最后的计算方法是:
- 根据有多少节点创建对应N数量的情侣组节点
- 遍历整个传入的数组,计算两两之间是否是同一组
- 如果不是同一组,就将两个元素对应的组连接起来
- 遍历连接后的nodes,计算结果
// 定义一个节点
class node {
constructor (i) {
// 将自己的父亲设为自己
this.parent = this
//记录下当前情侣座位的序号
this.seat = i
}
}
// 定义查找函数,不断查找父节点,直到父节点等于本身
const find = function (x) {
while(x !== x.parent) {
x = x.parent
}
return x
}
var minSwapsCouples = function(row) {
// 保存传入数组长度
let len = row.length;
// 保存对应数量情侣组数量
let cplen = len / 2
// 返回的结果
let res = 0
// 创建对应多个节点数组
// 通过传入的数组进行节点创建,对应的人的座位通过i,来确定
let nodes = Array(cplen).fill(0).map((x,i) => new node(i))
// 遍历整个传入的数组
for (let i = 0; i < len; i += 2) {
// 判断两个元素是否为同一组
// 如果这两个元素不是同一组的,那么对应的节点就要连接起来
if(Math.floor(row[i]/2) !== Math.floor(row[i+1]/2)) {
// 连接这个人对应的情侣座位节点
let r = Math.floor(row[i]/2)
let l = Math.floor(row[i+1]/2)
// 连接对应节点
find(nodes[r]).parent = find(nodes[l])
}
}
// 遍历整个nodes,返回结果
for(let i = 0;i<nodes.length;i++) {
// 如果当前节点的parent属性不是本身,那么他就是和别人连通的,那么就是要交换的
if(nodes[i].parent !== nodes[i]) res++
}
return res
};