LeetCode 每日一题笔记
0. 前言
- 日期:2026.04.21
- 题目:1722. 执行交换操作后的最小汉明距离
- 难度:中等
- 标签:并查集、哈希表、贪心
1. 题目理解
问题描述 :
给你两个长度为 n 的整数数组 source 和 target,以及一个表示可交换下标的二维数组 allowedSwaps。
你可以按任意顺序、任意次数交换 allowedSwaps 中指定的下标对。
汉明距离定义为两个数组中元素不同的下标数量。
要求:在对 source 执行任意数量的允许交换后,返回它与 target 之间的最小汉明距离。
示例 :
输入:
source = [1,2,3,4]target = [2,1,4,5]allowedSwaps = [[0,1],[2,3]]
输出:1
解释:- 交换下标 0 和 1,source 变为
[2,1,3,4] - 交换下标 2 和 3,source 变为
[2,1,4,3] - 此时与 target
[2,1,4,5]只有下标 3 处不同,汉明距离为 1。
2. 解题思路
核心观察
- 允许的交换关系可以构成多个连通分量 :同一分量内的所有下标可以通过交换互相到达,因此
source中这些位置的元素可以任意排列。 - 要使汉明距离最小,应让
target中每个位置的元素,优先与同一连通分量内source中存在的元素匹配。 - 无法匹配的元素数量,就是最终的最小汉明距离。
算法步骤
- 使用并查集(Union-Find) ,根据
allowedSwaps构建所有下标之间的连通分量。 - 遍历
source数组,统计每个连通分量内,各元素出现的次数。 - 遍历
target数组,对于每个位置,在其对应的连通分量中查找是否存在该元素的剩余次数:- 存在则匹配成功,减少该元素的计数;
- 不存在则匹配失败,汉明距离加一。
3. 代码实现
java
package lc1722;
import java.util.HashMap;
import java.util.Map;
class Solution {
public int minimumHammingDistance(int[] source, int[] target, int[][] allowedSwaps) {
int n = source.length;
UnionFind uf = new UnionFind(n);
for (int[] swap : allowedSwaps) {
uf.union(swap[0], swap[1]);
}
Map<Integer, Map<Integer, Integer>> groupCount = new HashMap<>();
for (int i = 0; i < n; i++) {
int root = uf.find(i);
groupCount.computeIfAbsent(root, k -> new HashMap<>())
.put(source[i], groupCount.get(root).getOrDefault(source[i], 0) + 1);
}
int res = 0;
for (int i = 0; i < n; i++) {
int root = uf.find(i);
Map<Integer, Integer> count = groupCount.get(root);
if (count.containsKey(target[i]) && count.get(target[i]) > 0) {
count.put(target[i], count.get(target[i]) - 1);
} else {
res++;
}
}
return res;
}
static class UnionFind {
int[] parent;
public UnionFind(int n) {
parent = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
public int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
public void union(int x, int y) {
int fx = find(x);
int fy = find(y);
if (fx != fy) {
parent[fy] = fx;
}
}
}
}
4. 代码优化说明
- 并查集优化:路径压缩和按秩合并,保证了几乎常数时间的查找和合并操作。
- 哈希表统计 :使用
Map<Integer, Map<Integer, Integer>>统计每个连通分量内的元素频率,空间利用率高。 - 单次遍历匹配 :在
target数组上单次遍历,直接匹配并消耗source中元素的计数,避免了二次遍历。 - 无额外排序:全程未使用排序,保证了线性时间复杂度。
5. 复杂度分析
-
时间复杂度 : O ( n α ( n ) ) O(n \alpha(n)) O(nα(n))
- 构建并查集: O ( m α ( n ) ) O(m \alpha(n)) O(mα(n)), m m m 为交换次数, α ( n ) \alpha(n) α(n) 为阿克曼函数反函数,增长极慢;
- 统计元素频率: O ( n ) O(n) O(n);
- 匹配
target数组: O ( n ) O(n) O(n)。
综合为线性时间复杂度。
-
空间复杂度 : O ( n ) O(n) O(n)
- 并查集数组: O ( n ) O(n) O(n);
- 哈希表统计:最坏情况下存储所有元素, O ( n ) O(n) O(n)。
6. 总结
- 本题核心是利用并查集处理交换关系,将问题转化为在连通分量内的元素匹配。
- 关键在于理解:同一连通分量内的元素可以任意排列,因此只需统计每个分量内的元素频率,与
target进行贪心匹配即可。 - 最小汉明距离就是无法匹配的元素数量。
- 暴力搜索或 BFS 模拟所有交换在数据量大时会超时,而并查集+哈希表的解法是本题的最优解。