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 模拟所有交换在数据量大时会超时,而并查集+哈希表的解法是本题的最优解。
相关推荐
鲸渔2 小时前
【C++ 跳转语句】break、continue、goto 与 return
开发语言·c++·算法
AI科技星2 小时前
基于螺旋元逻辑的宇宙统一场论底层公理构建(乖乖数学)
算法·机器学习·数学建模·数据挖掘·量子计算
qiqsevenqiqiqiqi2 小时前
MC0550鱼肠剑试锋芒
数据结构·算法
仍然.2 小时前
算法题目---链表
数据结构·算法·链表
luoganttcc2 小时前
华为昇腾(Ascend)等芯片,同样存在“寄存器 / 片上存储资源限制并发”的问题
算法·华为
小O的算法实验室3 小时前
2025年SEVC,神经-粒子群算法+大规模动态优化,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
wayz113 小时前
Day 7:第一周复习与模型综合比较
人工智能·算法·机器学习·量化交易
玛丽莲茼蒿3 小时前
Leetcode hot100 买卖股票的最佳时机【简单】
算法·leetcode·职场和发展
阿Y加油吧3 小时前
两道 LeetCode 题的复盘笔记:从「只会暴力」到「懂优化」
笔记·算法·leetcode