# [765. 情侣牵手](https://leetcode.cn/problems/couples-holding-hands) [English Version](/solution/0700-0799/0765.Couples%20Holding%20Hands/README_EN.md) <!-- tags:贪心,深度优先搜索,广度优先搜索,并查集,图 --> ## 题目描述 <!-- 这里写题目描述 --> <p><code>n</code> 对情侣坐在连续排列的 <code>2n</code> 个座位上,想要牵到对方的手。</p> <p>人和座位由一个整数数组 <code>row</code> 表示,其中 <code>row[i]</code> 是坐在第 <code>i </code>个座位上的人的 <strong>ID</strong>。情侣们按顺序编号,第一对是 <code>(0, 1)</code>,第二对是 <code>(2, 3)</code>,以此类推,最后一对是 <code>(2n-2, 2n-1)</code>。</p> <p>返回 <em>最少交换座位的次数,以便每对情侣可以并肩坐在一起</em>。 <i>每次</i>交换可选择任意两人,让他们站起来交换座位。</p> <p> </p> <p><strong>示例 1:</strong></p> <pre> <strong>输入:</strong> row = [0,2,1,3] <strong>输出:</strong> 1 <strong>解释:</strong> 只需要交换row[1]和row[2]的位置即可。 </pre> <p><strong>示例 2:</strong></p> <pre> <strong>输入:</strong> row = [3,2,0,1] <strong>输出:</strong> 0 <strong>解释:</strong> 无需交换座位,所有的情侣都已经可以手牵手了。 </pre> <p> </p> <p><strong>提示:</strong></p> <ul> <li><code>2n == row.length</code></li> <li><code>2 <= n <= 30</code></li> <li><code>n</code> 是偶数</li> <li><code>0 <= row[i] < 2n</code></li> <li><code>row</code> 中所有元素均<strong>无重复</strong></li> </ul> ## 解法 ### 方法一:并查集 我们可以给每一对情侣编号,编号 $0$ 和 $1$ 的人对应情侣 $0$,编号 $2$ 和 $3$ 的人对应情侣 $1$...即编号为 $row[i]$ 对应的情侣编号为 $\lfloor \frac{row[i]}{2} \rfloor$。 如果有 $k$ 对情侣相互之间坐错了位置,也即是说,有 $k$ 对情侣处于一个置换环中,那么他们之间需要经过 $k-1$ 次交换才能都坐到正确的位置上。 为什么?不妨这样考虑,我们先调整一对情侣的位置,使其坐到正确的位置上,那么问题就从 $k$ 对情侣的问题,转换成了 $k-1$ 对情侣的问题。依此类推,最终 $k=1$ 时,交换次数为 $0$。所以,如果 $k$ 对情侣相互之间坐错了位置,那么需要 $k-1$ 次交换。 因此,我们只需要遍历一遍数组,利用并查集找出有多少个置换环,假设有 $x$ 个,每个环的大小(情侣的对数)为 $y_1, y_2, \cdots, y_x$,那么需要交换的次数为 $y_1-1 + y_2-1 + \cdots + y_x-1 = y_1 + y_2 + \cdots + y_x - x = n - x$。 时间复杂度 $O(n \times \alpha(n))$,空间复杂度 $O(n)$。其中 $\alpha(n)$ 为阿克曼函数的反函数,可以认为是一个很小的常数。 <!-- tabs:start --> ```python class Solution: def minSwapsCouples(self, row: List[int]) -> int: def find(x: int) -> int: if p[x] != x: p[x] = find(p[x]) return p[x] n = len(row) >> 1 p = list(range(n)) for i in range(0, len(row), 2): a, b = row[i] >> 1, row[i + 1] >> 1 p[find(a)] = find(b) return n - sum(i == find(i) for i in range(n)) ``` ```java class Solution { private int[] p; public int minSwapsCouples(int[] row) { int n = row.length >> 1; p = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; } for (int i = 0; i < n << 1; i += 2) { int a = row[i] >> 1, b = row[i + 1] >> 1; p[find(a)] = find(b); } int ans = n; for (int i = 0; i < n; ++i) { if (i == find(i)) { --ans; } } return ans; } private int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } } ``` ```cpp class Solution { public: int minSwapsCouples(vector<int>& row) { int n = row.size() / 2; int p[n]; iota(p, p + n, 0); function<int(int)> find = [&](int x) -> int { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; }; for (int i = 0; i < n << 1; i += 2) { int a = row[i] >> 1, b = row[i + 1] >> 1; p[find(a)] = find(b); } int ans = n; for (int i = 0; i < n; ++i) { ans -= i == find(i); } return ans; } }; ``` ```go func minSwapsCouples(row []int) int { n := len(row) >> 1 p := make([]int, n) for i := range p { p[i] = i } var find func(int) int find = func(x int) int { if p[x] != x { p[x] = find(p[x]) } return p[x] } for i := 0; i < n<<1; i += 2 { a, b := row[i]>>1, row[i+1]>>1 p[find(a)] = find(b) } ans := n for i := range p { if find(i) == i { ans-- } } return ans } ``` ```ts function minSwapsCouples(row: number[]): number { const n = row.length >> 1; const p: number[] = Array(n) .fill(0) .map((_, i) => i); const find = (x: number): number => { if (p[x] !== x) { p[x] = find(p[x]); } return p[x]; }; for (let i = 0; i < n << 1; i += 2) { const a = row[i] >> 1; const b = row[i + 1] >> 1; p[find(a)] = find(b); } let ans = n; for (let i = 0; i < n; ++i) { if (i === find(i)) { --ans; } } return ans; } ``` ```cs public class Solution { private int[] p; public int MinSwapsCouples(int[] row) { int n = row.Length >> 1; p = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; } for (int i = 0; i < n << 1; i += 2) { int a = row[i] >> 1; int b = row[i + 1] >> 1; p[find(a)] = find(b); } int ans = n; for (int i = 0; i < n; ++i) { if (p[i] == i) { --ans; } } return ans; } private int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; } } ``` <!-- tabs:end --> <!-- end -->