LeetCode 每日一题笔记 日期:2026.04.21 题目:1722. 执行交换操作后的最小汉明距离

LeetCode 每日一题笔记

0. 前言

  • 日期:2026.04.21
  • 题目:1722. 执行交换操作后的最小汉明距离
  • 难度:中等
  • 标签:并查集、哈希表、贪心

1. 题目理解

问题描述

给你两个长度为 n 的整数数组 sourcetarget,以及一个表示可交换下标的二维数组 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. 解题思路

核心观察

  1. 允许的交换关系可以构成多个连通分量 :同一分量内的所有下标可以通过交换互相到达,因此 source 中这些位置的元素可以任意排列。
  2. 要使汉明距离最小,应让 target 中每个位置的元素,优先与同一连通分量内 source 中存在的元素匹配。
  3. 无法匹配的元素数量,就是最终的最小汉明距离。

算法步骤

  1. 使用并查集(Union-Find) ,根据 allowedSwaps 构建所有下标之间的连通分量。
  2. 遍历 source 数组,统计每个连通分量内,各元素出现的次数。
  3. 遍历 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. 代码优化说明

  1. 并查集优化:路径压缩和按秩合并,保证了几乎常数时间的查找和合并操作。
  2. 哈希表统计 :使用 Map<Integer, Map<Integer, Integer>> 统计每个连通分量内的元素频率,空间利用率高。
  3. 单次遍历匹配 :在 target 数组上单次遍历,直接匹配并消耗 source 中元素的计数,避免了二次遍历。
  4. 无额外排序:全程未使用排序,保证了线性时间复杂度。

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 模拟所有交换在数据量大时会超时,而并查集+哈希表的解法是本题的最优解。
相关推荐
爱喝雪碧的可乐8 小时前
2026 腾讯广告算法大赛优秀方案启示:行为条件化多模态自回归生成推荐摘要
算法·数据挖掘·回归·推荐系统·推荐算法
碧海银沙音频科技研究院8 小时前
音箱在加入 NN AEC(神经网络声学回声消除) 后出现反复重启问题解决
人工智能·深度学习·算法
小陈phd8 小时前
多模态大模型学习笔记(四十)——从“看字”到“懂结构”:版面分析与表格解析技术全解
笔记·学习
xuhaoyu_cpp_java8 小时前
SpringMVC学习(二)
java·经验分享·笔记·学习·spring
叼烟扛炮10 小时前
C++ 知识点18 内部类
开发语言·c++·算法·内部类
YOGOD有神10 小时前
用AI自动从谷歌地图抓取海外客户,我跑了一次7小时的任务,结果出乎意料
算法
噜噜噜阿鲁~10 小时前
python学习笔记 | 9.2、模块-安装第三方模块
笔记·python·学习
汉克老师10 小时前
GESP5级C++考试语法知识(十五、分治算法(二))
c++·算法·排序算法·分治算法·gesp5级·gesp五级
快瞳科技10 小时前
小样本学习在珍稀鸟类识别中的突破:仅需5张图,让AI认识濒危物种
算法
汉克老师10 小时前
GESP6级C++考试语法知识(五、格雷码)
c++·算法·位运算·异或·gesp6级·gesp六级·格雷码