题目
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]的位置即可。
题解
贪心
- 既然情侣必须相邻,假设任意情侣分别为甲、乙
- 枚举数组,遇到情侣不相邻,帮当前的情侣甲找到情侣乙
- 怎么帮?
- 比如遇到了情侣4,他需要5坐在他下一位置,你把5从茫茫人海中找到不就完了。
- 怎么找?
- 比如数组[4,2,0,1,3,5]
- 第1位是4,需要把5放在第2位;但是5在第6位,把第6位与第2位交换得到[4,5,0,1,3,2]
- 然后情侣[4,5]就坐好了,再接着在[4,5,0,1,3,2]第3位开始
- 第3位是0,第4位是1;他俩是情侣,不需要
- 第5位是3,第6位是2,又是情侣,不需要交换
- 整个过程交换1次答案1;
- 根据上述思路,代码如下
代码
var minSwapsCouples = function (row) {
const len = row.length
const indexMap = {}
for (let i = 0; i < len; i++) {
const k = row[i]
indexMap[k] = i
}
let result = 0
for (let i = 0; i < len - 2; i += 2) {
if ((row[i] ^ 1) === row[i + 1]) continue
// 下一位置的值
const next = row[i + 1]
const nextIndx = indexMap[next]
// 需要的值,需要的值位置在i+1处
const should = row[i] ^ 1
const shouldIdx = indexMap[should]
row[nextIndx] = should
row[shouldIdx] = next
indexMap[next] = shouldIdx
indexMap[should] = nextIndx
// 交换map中数据
result++
}
return result
}
并查集
- 如果有情侣座错位置,那最少有2对情侣座错位置
- 如果2对情侣座错位置,只需要交换1次即可
- 如果3对情侣座错位置,只需要交换2次即可
- ...
- 如果n对情侣座错位置,只需要交换n-1次即可
- 如何判断几对情侣座错位置?
- 并查集
- 并查集的关联关系是什么?
- 寻找座错的情侣,如果情侣位置上对的,对任意位置x; 有row[x]>>2 === row[x+1]>>2
- 如果情侣位置不对,row[x]>>2 !== row[x+1]>>2;
- 座错位置的情侣会被合并到一个集合中
- 统计集合中有多找坐对位置的情侣
- 情侣对数量-做对位置的情侣数即可得到答案
以上思路并非我自己想到的,参考的宫水三叶大神的思路;
代码
var minSwapsCouples = function (row) {
const len = row.length
const list = Array(len / 2)
.fill(0)
.map((v, i) => i)
for (let i = 0; i < len; i += 2) {
const current = row[i] >> 1
const next = row[i + 1] >> 1
merge(current, next)
}
let ring = 0
for (let i = 0; i < len / 2; i++) {
if (i === find(i)) ring++
}
return len / 2 - ring
function merge(x, y) {
const rootX = find(x)
const rootY = find(y)
list[rootX] = rootY
}
function find(n) {
if (list[n] === n) return list[n]
const root = find(list[n])
list[n] = root
return root
}
}
结语
我是软件开发工程师,不是月老;情侣不自己找相邻位置坐,为难我们写程序的干啥