@@ -55,70 +55,13 @@ source 和 target 间的汉明距离是 2 ,二者有 2 处元素不同,在
55
55
56
56
<!-- 这里可写通用的实现逻辑 -->
57
57
58
- 并查集。
58
+ ** 方法一: 并查集 + 哈希表 **
59
59
60
- 模板 1——朴素并查集:
61
-
62
- ``` python
63
- # 初始化,p存储每个点的父节点
64
- p = list (range (n))
65
-
66
-
67
- # 返回x的祖宗节点
68
- def find (x ):
69
- if p[x] != x:
70
- # 路径压缩
71
- p[x] = find(p[x])
72
- return p[x]
73
-
74
-
75
- # 合并a和b所在的两个集合
76
- p[find(a)] = find(b)
77
- ```
78
-
79
- 模板 2——维护 size 的并查集:
80
-
81
- ``` python
82
- # 初始化,p存储每个点的父节点,size只有当节点是祖宗节点时才有意义,表示祖宗节点所在集合中,点的数量
83
- p = list (range (n))
84
- size = [1 ] * n
85
-
86
-
87
- # 返回x的祖宗节点
88
- def find (x ):
89
- if p[x] != x:
90
- # 路径压缩
91
- p[x] = find(p[x])
92
- return p[x]
60
+ 我们可以将每个下标看作一个节点,每个下标对应的元素看作节点的值,那么给定的 ` allowedSwaps ` 中的每个元素 ` [a_i, b_i] ` 就表示下标 ` a_i ` 和 ` b_i ` 之间存在一条边。因此,我们可以使用并查集来维护这些连通分量。
93
61
62
+ 在得到每个连通分量之后,我们再用二维哈希表 $cnt$ 分别统计每个连通分量中每个元素出现的次数,最后对于数组 ` target ` 中的每个元素,如果其在对应的连通分量中出现的次数大于 0,则将其出现次数减 1,否则将答案加 1。
94
63
95
- # 合并a和b所在的两个集合
96
- if find(a) != find(b):
97
- size[find(b)] += size[find(a)]
98
- p[find(a)] = find(b)
99
- ```
100
-
101
- 模板 3——维护到祖宗节点距离的并查集:
102
-
103
- ``` python
104
- # 初始化,p存储每个点的父节点,d[x]存储x到p[x]的距离
105
- p = list (range (n))
106
- d = [0 ] * n
107
-
108
-
109
- # 返回x的祖宗节点
110
- def find (x ):
111
- if p[x] != x:
112
- t = find(p[x])
113
- d[x] += d[p[x]]
114
- p[x] = t
115
- return p[x]
116
-
117
-
118
- # 合并a和b所在的两个集合
119
- p[find(a)] = find(b)
120
- d[find(a)] = distance
121
- ```
64
+ 时间复杂度 $O(n \times \log n)$ 或 $O(n \times \alpha(n))$,空间复杂度 $O(n)$。其中 $n$ 是数组的长度,而 $\alpha$ 是阿克曼函数的反函数。
122
65
123
66
<!-- tabs:start -->
124
67
@@ -131,27 +74,25 @@ class Solution:
131
74
def minimumHammingDistance (
132
75
self , source : List[int ], target : List[int ], allowedSwaps : List[List[int ]]
133
76
) -> int :
134
- n = len (source)
135
- p = list (range (n))
136
-
137
- def find (x ):
77
+ def find (x : int ) -> int :
138
78
if p[x] != x:
139
79
p[x] = find(p[x])
140
80
return p[x]
141
81
142
- for i, j in allowedSwaps:
143
- p[find(i)] = find(j)
144
-
145
- mp = defaultdict(Counter)
146
- for i in range (n):
147
- mp[find(i)][source[i]] += 1
148
- res = 0
149
- for i in range (n):
150
- if mp[find(i)][target[i]] > 0 :
151
- mp[find(i)][target[i]] -= 1
152
- else :
153
- res += 1
154
- return res
82
+ n = len (source)
83
+ p = list (range (n))
84
+ for a, b in allowedSwaps:
85
+ p[find(a)] = find(b)
86
+ cnt = defaultdict(Counter)
87
+ for i, x in enumerate (source):
88
+ j = find(i)
89
+ cnt[j][x] += 1
90
+ ans = 0
91
+ for i, x in enumerate (target):
92
+ j = find(i)
93
+ cnt[j][x] -= 1
94
+ ans += cnt[j][x] < 0
95
+ return ans
155
96
```
156
97
157
98
### ** Java**
@@ -165,28 +106,26 @@ class Solution {
165
106
public int minimumHammingDistance (int [] source , int [] target , int [][] allowedSwaps ) {
166
107
int n = source. length;
167
108
p = new int [n];
168
- for (int i = 0 ; i < n; ++ i ) {
109
+ for (int i = 0 ; i < n; i ++ ) {
169
110
p[i] = i;
170
111
}
171
- for (int [] e : allowedSwaps) {
172
- p[find(e [0 ])] = find(e [1 ]);
112
+ for (int [] a : allowedSwaps) {
113
+ p[find(a [0 ])] = find(a [1 ]);
173
114
}
174
- Map<Integer , Map<Integer , Integer > > mp = new HashMap<> ();
115
+ Map<Integer , Map<Integer , Integer > > cnt = new HashMap<> ();
175
116
for (int i = 0 ; i < n; ++ i) {
176
- int root = find(i);
177
- mp. computeIfAbsent(root, k - > new HashMap<> ())
178
- .put(source[i], mp. get(root). getOrDefault(source[i], 0 ) + 1 );
117
+ int j = find(i);
118
+ cnt. computeIfAbsent(j, k - > new HashMap<> ()). merge(source[i], 1 , Integer :: sum);
179
119
}
180
- int res = 0 ;
120
+ int ans = 0 ;
181
121
for (int i = 0 ; i < n; ++ i) {
182
- int root = find(i);
183
- if (mp. get(root). getOrDefault(target[i], 0 ) > 0 ) {
184
- mp. get(root). put(target[i], mp. get(root). get(target[i]) - 1 );
185
- } else {
186
- ++ res;
122
+ int j = find(i);
123
+ Map<Integer , Integer > t = cnt. get(j);
124
+ if (t. merge(target[i], - 1 , Integer :: sum) < 0 ) {
125
+ ++ ans;
187
126
}
188
127
}
189
- return res ;
128
+ return ans ;
190
129
}
191
130
192
131
private int find (int x ) {
@@ -203,69 +142,107 @@ class Solution {
203
142
``` cpp
204
143
class Solution {
205
144
public:
206
- vector<int > p;
207
-
208
145
int minimumHammingDistance(vector<int >& source, vector<int >& target, vector<vector<int >>& allowedSwaps) {
209
146
int n = source.size();
210
- p.resize(n);
211
- for (int i = 0; i < n; ++i) p[i] = i;
212
- for (auto e : allowedSwaps) p[find(e[0])] = find(e[1]);
213
- unordered_map<int, unordered_map<int, int>> mp;
214
- for (int i = 0; i < n; ++i) ++mp[find(i)][source[i]];
215
- int res = 0;
147
+ vector<int > p(n);
148
+ iota(p.begin(), p.end(), 0);
149
+ function<int(int)> find = [ &] (int x) {
150
+ return x == p[ x] ? x : p[ x] = find(p[ x] );
151
+ };
152
+ for (auto& a : allowedSwaps) {
153
+ p[ find(a[ 0] )] = find(a[ 1] );
154
+ }
155
+ unordered_map<int, unordered_map<int, int>> cnt;
216
156
for (int i = 0; i < n; ++i) {
217
- if (mp[find(i)][target[i]] > 0)
218
- --mp[find(i)][target[i]];
219
- else
220
- ++res;
157
+ ++cnt[ find(i)] [ source[ i]] ;
221
158
}
222
- return res;
223
- }
224
-
225
- int find (int x) {
226
- if (p[ x] != x) p[ x] = find(p[ x] );
227
- return p[ x] ;
159
+ int ans = 0;
160
+ for (int i = 0; i < n; ++i) {
161
+ if (--cnt[ find(i)] [ target[ i]] < 0) {
162
+ ++ans;
163
+ }
164
+ }
165
+ return ans;
228
166
}
229
167
};
230
168
```
231
169
232
170
### **Go**
233
171
234
172
```go
235
- var p []int
236
-
237
- func minimumHammingDistance(source []int, target []int, allowedSwaps [][]int) int {
173
+ func minimumHammingDistance(source []int, target []int, allowedSwaps [][]int) (ans int) {
238
174
n := len(source)
239
- p = make([]int, n)
240
- for i := 0; i < n; i++ {
175
+ p : = make([]int, n)
176
+ for i := range p {
241
177
p[i] = i
242
178
}
243
- for _, e := range allowedSwaps {
244
- p[find(e[0])] = find(e[1])
179
+ var find func(int) int
180
+ find = func(x int) int {
181
+ if p[x] != x {
182
+ p[x] = find(p[x])
183
+ }
184
+ return p[x]
185
+ }
186
+ for _, a := range allowedSwaps {
187
+ p[find(a[0])] = find(a[1])
245
188
}
246
- mp := make(map[int]map[int]int)
247
- for i := 0; i < n; i++ {
248
- if mp[find(i)] == nil {
249
- mp[find(i)] = make(map[int]int)
189
+ cnt := map[int]map[int]int{}
190
+ for i, x := range source {
191
+ j := find(i)
192
+ if cnt[j] == nil {
193
+ cnt[j] = map[int]int{}
250
194
}
251
- mp[find(i)][source[i] ]++
195
+ cnt[j][x ]++
252
196
}
253
- res := 0
254
- for i := 0; i < n; i++ {
255
- if mp[find(i)][target[i]] > 0 {
256
- mp[find(i)][target[i]]--
257
- } else {
258
- res++
197
+ for i, x := range target {
198
+ j := find(i)
199
+ cnt[j][x]--
200
+ if cnt[j][x] < 0 {
201
+ ans++
259
202
}
260
203
}
261
- return res
204
+ return
262
205
}
206
+ ```
263
207
264
- func find(x int) int {
265
- if p[x] != x {
266
- p[x] = find(p[x])
267
- }
268
- return p[x]
208
+ ### ** TypeScript**
209
+
210
+ ``` ts
211
+ function minimumHammingDistance(
212
+ source : number [],
213
+ target : number [],
214
+ allowedSwaps : number [][],
215
+ ): number {
216
+ const n = source .length ;
217
+ const p: number [] = Array .from ({ length: n }, (_ , i ) => i );
218
+ const find = (x : number ): number => {
219
+ if (p [x ] !== x ) {
220
+ p [x ] = find (p [x ]);
221
+ }
222
+ return p [x ];
223
+ };
224
+ for (const [a, b] of allowedSwaps ) {
225
+ p [find (a )] = find (b );
226
+ }
227
+ const cnt: Map <number , Map <number , number >> = new Map ();
228
+ for (let i = 0 ; i < n ; ++ i ) {
229
+ const j = find (i );
230
+ if (! cnt .has (j )) {
231
+ cnt .set (j , new Map ());
232
+ }
233
+ const m = cnt .get (j )! ;
234
+ m .set (source [i ], (m .get (source [i ]) ?? 0 ) + 1 );
235
+ }
236
+ let ans = 0 ;
237
+ for (let i = 0 ; i < n ; ++ i ) {
238
+ const j = find (i );
239
+ const m = cnt .get (j )! ;
240
+ m .set (target [i ], (m .get (target [i ]) ?? 0 ) - 1 );
241
+ if (m .get (target [i ])! < 0 ) {
242
+ ++ ans ;
243
+ }
244
+ }
245
+ return ans ;
269
246
}
270
247
```
271
248
0 commit comments