46
46
47
47
<!-- 这里可写通用的实现逻辑 -->
48
48
49
- 坐错位置的情况与最少需要交换次数:
49
+ ** 方法一:并查集 **
50
50
51
- - 1 对情侣、2 个座位,不需要交换。
52
- - 2 对情侣、4 个座位,交换 1 次。
53
- - 3 对情侣、6 个座位。首先交换 1 次使得其中 1 对情侣坐在一起,剩下 2 对情侣、4 个座位。即需要交换 2 次。
51
+ 我们可以给每一对情侣编号,编号 $0$ 和 $1$ 的人对应情侣 $0$,编号 $2$ 和 $3$ 的人对应情侣 $1$...即编号为 $row[ i] $ 对应的情侣编号为 $\lfloor \frac{row[ i] }{2} \rfloor$。
54
52
55
- 以此类推,得到 ` f(n)=n-1 ` 。即:n 对情侣相互坐错位置,最少需要交换 ` n-1 ` 次 。
53
+ 如果有 $k$ 对情侣相互之间坐错了位置,也即是说,有 $k$ 对情侣处于一个置换环中,那么他们之间需要经过 $k-1$ 次交换才能都坐到正确的位置上 。
56
54
57
- 把相互坐错位置的情侣放在一组(同个集合),组内有 n 对情侣就需要 ` n-1 ` 次交换。将 n 对情侣分为 K 组:N1,N2...Nk,有 N1+N2+...+Nk=n。需要交换的次数分别为:N1-1、N2-1、...、Nk-1,则总的最少交换次数为 N1-1+N2-1+...+Nk-1=N1+N2+...+Nk-k=n-k。问题转换为:n 对情侣,根据相互坐错位置的条件分组,共有多少个分组。并查集实现 。
55
+ 为什么?不妨这样考虑,我们先调整一对情侣的位置,使其坐到正确的位置上,那么问题就从 $k$ 对情侣的问题,转换成了 $k-1$ 对情侣的问题。依此类推,最终 $k=1$ 时,交换次数为 $0$。所以,如果 $k$ 对情侣相互之间坐错了位置,那么需要 $k-1$ 次交换 。
58
56
59
- 模板 1——朴素并查集:
57
+ 因此,我们只需要遍历一遍数组,利用并查集找出有多少个置换环,假设有 $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$。
60
58
61
- ``` python
62
- # 初始化,p存储每个点的父节点
63
- p = list (range (n))
64
-
65
- # 返回x的祖宗节点
66
- def find (x ):
67
- if p[x] != x:
68
- # 路径压缩
69
- p[x] = find(p[x])
70
- return p[x]
71
-
72
-
73
- # 合并a和b所在的两个集合
74
- p[find(a)] = find(b)
75
- ```
76
-
77
- 模板 2——维护 size 的并查集:
78
-
79
- ``` python
80
- # 初始化,p存储每个点的父节点,size只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量
81
- p = list (range (n))
82
- size = [1 ] * n
83
-
84
- # 返回x的祖宗节点
85
- def find (x ):
86
- if p[x] != x:
87
- # 路径压缩
88
- p[x] = find(p[x])
89
- return p[x]
90
-
91
- # 合并a和b所在的两个集合
92
- if find(a) != find(b):
93
- size[find(b)] += size[find(a)]
94
- p[find(a)] = find(b)
95
- ```
96
-
97
- 模板 3——维护到祖宗节点距离的并查集:
98
-
99
- ``` python
100
- # 初始化,p存储每个点的父节点,d[x]存储x到p[x]的距离
101
- p = list (range (n))
102
- d = [0 ] * n
103
-
104
- # 返回x的祖宗节点
105
- def find (x ):
106
- if p[x] != x:
107
- t = find(p[x])
108
- d[x] += d[p[x]]
109
- p[x] = t
110
- return p[x]
111
-
112
- # 合并a和b所在的两个集合
113
- p[find(a)] = find(b)
114
- d[find(a)] = distance
115
- ```
59
+ 时间复杂度 $O(n \times \alpha(n))$,空间复杂度 $O(n)$。其中 $\alpha(n)$ 为阿克曼函数的反函数,可以认为是一个很小的常数。
116
60
117
61
<!-- tabs:start -->
118
62
@@ -123,7 +67,7 @@ d[find(a)] = distance
123
67
``` python
124
68
class Solution :
125
69
def minSwapsCouples (self , row : List[int ]) -> int :
126
- def find (x ) :
70
+ def find (x : int ) -> int :
127
71
if p[x] != x:
128
72
p[x] = find(p[x])
129
73
return p[x]
@@ -150,17 +94,17 @@ class Solution {
150
94
for (int i = 0 ; i < n; ++ i) {
151
95
p[i] = i;
152
96
}
153
- for (int i = 0 ; i < row . length ; i += 2 ) {
97
+ for (int i = 0 ; i < n << 1 ; i += 2 ) {
154
98
int a = row[i] >> 1 , b = row[i + 1 ] >> 1 ;
155
99
p[find(a)] = find(b);
156
100
}
157
- int cnt = 0 ;
101
+ int ans = n ;
158
102
for (int i = 0 ; i < n; ++ i) {
159
103
if (i == find(i)) {
160
- ++ cnt ;
104
+ -- ans ;
161
105
}
162
106
}
163
- return n - cnt ;
107
+ return ans ;
164
108
}
165
109
166
110
private int find (int x ) {
@@ -177,64 +121,120 @@ class Solution {
177
121
``` cpp
178
122
class Solution {
179
123
public:
180
- vector<int > p;
181
-
182
124
int minSwapsCouples(vector<int >& row) {
183
- int n = row.size() >> 1;
184
- p.resize(n);
185
- for (int i = 0; i < n; ++i) {
186
- p[i] = i;
187
- }
188
- for (int i = 0 ; i < row.size(); i += 2 ) {
125
+ int n = row.size() / 2;
126
+ int p[ n] ;
127
+ iota(p, p + n, 0);
128
+ function<int(int)> find = [ &] (int x) -> int {
129
+ if (p[ x] != x) {
130
+ p[ x] = find(p[ x] );
131
+ }
132
+ return p[ x] ;
133
+ };
134
+ for (int i = 0; i < n << 1; i += 2) {
189
135
int a = row[ i] >> 1, b = row[ i + 1] >> 1;
190
136
p[ find(a)] = find(b);
191
137
}
192
- int cnt = 0 ;
138
+ int ans = n ;
193
139
for (int i = 0; i < n; ++i) {
194
- if (i == find(i))
195
- ++cnt;
140
+ ans -= i == find(i);
196
141
}
197
- return n - cnt;
198
- }
199
-
200
- int find(int x) {
201
- if (p[x] != x) {
202
- p[x] = find(p[x]);
203
- }
204
- return p[x];
142
+ return ans;
205
143
}
206
144
};
207
145
```
208
146
209
147
### **Go**
210
148
211
149
```go
212
- var p []int
213
-
214
150
func minSwapsCouples(row []int) int {
215
151
n := len(row) >> 1
216
- p = make ([]int , n)
217
- for i := 0 ; i < n; i++ {
152
+ p : = make([]int, n)
153
+ for i := range p {
218
154
p[i] = i
219
155
}
220
- for i := 0 ; i < len (row); i += 2 {
156
+ var find func(int) int
157
+ find = func(x int) int {
158
+ if p[x] != x {
159
+ p[x] = find(p[x])
160
+ }
161
+ return p[x]
162
+ }
163
+ for i := 0; i < n<<1; i += 2 {
221
164
a, b := row[i]>>1, row[i+1]>>1
222
165
p[find(a)] = find(b)
223
166
}
224
- cnt := 0
225
- for i := 0 ; i < n; i++ {
226
- if i == find (i) {
227
- cnt++
167
+ ans := n
168
+ for i := range p {
169
+ if find(i) == i {
170
+ ans--
228
171
}
229
172
}
230
- return n - cnt
173
+ return ans
231
174
}
175
+ ```
232
176
233
- func find (x int ) int {
234
- if p[x] != x {
235
- p[x] = find (p[x])
236
- }
237
- return p[x]
177
+ ### ** TypeScript**
178
+
179
+ ``` ts
180
+ function minSwapsCouples(row : number []): number {
181
+ const n = row .length >> 1 ;
182
+ const p: number [] = Array (n )
183
+ .fill (0 )
184
+ .map ((_ , i ) => i );
185
+ const find = (x : number ): number => {
186
+ if (p [x ] !== x ) {
187
+ p [x ] = find (p [x ]);
188
+ }
189
+ return p [x ];
190
+ };
191
+ for (let i = 0 ; i < n << 1 ; i += 2 ) {
192
+ const a = row [i ] >> 1 ;
193
+ const b = row [i + 1 ] >> 1 ;
194
+ p [find (a )] = find (b );
195
+ }
196
+ let ans = n ;
197
+ for (let i = 0 ; i < n ; ++ i ) {
198
+ if (i === find (i )) {
199
+ -- ans ;
200
+ }
201
+ }
202
+ return ans ;
203
+ }
204
+ ```
205
+
206
+ ### ** C#**
207
+
208
+ ``` cs
209
+ public class Solution {
210
+ private int [] p ;
211
+
212
+ public int MinSwapsCouples (int [] row ) {
213
+ int n = row .Length >> 1 ;
214
+ p = new int [n ];
215
+ for (int i = 0 ; i < n ; ++ i ) {
216
+ p [i ] = i ;
217
+ }
218
+ for (int i = 0 ; i < n << 1 ; i += 2 ) {
219
+ int a = row [i ] >> 1 ;
220
+ int b = row [i + 1 ] >> 1 ;
221
+ p [find (a )] = find (b );
222
+ }
223
+ int ans = n ;
224
+ for (int i = 0 ; i < n ; ++ i ) {
225
+ if (p [i ] == i ) {
226
+ -- ans ;
227
+ }
228
+ }
229
+ return ans ;
230
+ }
231
+
232
+ private int find (int x ) {
233
+ if (p [x ] != x ) {
234
+ p [x ] = find (p [x ]);
235
+ }
236
+ return p [x ];
237
+ }
238
238
}
239
239
```
240
240
0 commit comments