Skip to content

Commit 57c9a87

Browse files
authored
feat: add solutions to lc problems: No.1722,1725 (doocs#2123)
No.1722.Minimize Hamming Distance After Swap Operations No.1725.Number Of Rectangles That Can Form The Largest Square
1 parent 7dd196b commit 57c9a87

File tree

14 files changed

+528
-465
lines changed

14 files changed

+528
-465
lines changed

solution/1700-1799/1722.Minimize Hamming Distance After Swap Operations/README.md

+111-134
Original file line numberDiff line numberDiff line change
@@ -55,70 +55,13 @@ source 和 target 间的汉明距离是 2 ,二者有 2 处元素不同,在
5555

5656
<!-- 这里可写通用的实现逻辑 -->
5757

58-
并查集
58+
**方法一:并查集 + 哈希表**
5959

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` 之间存在一条边。因此,我们可以使用并查集来维护这些连通分量。
9361

62+
在得到每个连通分量之后,我们再用二维哈希表 $cnt$ 分别统计每个连通分量中每个元素出现的次数,最后对于数组 `target` 中的每个元素,如果其在对应的连通分量中出现的次数大于 0,则将其出现次数减 1,否则将答案加 1。
9463

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$ 是阿克曼函数的反函数。
12265

12366
<!-- tabs:start -->
12467

@@ -131,27 +74,25 @@ class Solution:
13174
def minimumHammingDistance(
13275
self, source: List[int], target: List[int], allowedSwaps: List[List[int]]
13376
) -> int:
134-
n = len(source)
135-
p = list(range(n))
136-
137-
def find(x):
77+
def find(x: int) -> int:
13878
if p[x] != x:
13979
p[x] = find(p[x])
14080
return p[x]
14181

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
15596
```
15697

15798
### **Java**
@@ -165,28 +106,26 @@ class Solution {
165106
public int minimumHammingDistance(int[] source, int[] target, int[][] allowedSwaps) {
166107
int n = source.length;
167108
p = new int[n];
168-
for (int i = 0; i < n; ++i) {
109+
for (int i = 0; i < n; i++) {
169110
p[i] = i;
170111
}
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]);
173114
}
174-
Map<Integer, Map<Integer, Integer>> mp = new HashMap<>();
115+
Map<Integer, Map<Integer, Integer>> cnt = new HashMap<>();
175116
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);
179119
}
180-
int res = 0;
120+
int ans = 0;
181121
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;
187126
}
188127
}
189-
return res;
128+
return ans;
190129
}
191130

192131
private int find(int x) {
@@ -203,69 +142,107 @@ class Solution {
203142
```cpp
204143
class Solution {
205144
public:
206-
vector<int> p;
207-
208145
int minimumHammingDistance(vector<int>& source, vector<int>& target, vector<vector<int>>& allowedSwaps) {
209146
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;
216156
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]];
221158
}
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;
228166
}
229167
};
230168
```
231169
232170
### **Go**
233171
234172
```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) {
238174
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 {
241177
p[i] = i
242178
}
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])
245188
}
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{}
250194
}
251-
mp[find(i)][source[i]]++
195+
cnt[j][x]++
252196
}
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++
259202
}
260203
}
261-
return res
204+
return
262205
}
206+
```
263207

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;
269246
}
270247
```
271248

0 commit comments

Comments
 (0)