Leetcode5650. 执行交换操作后的最小汉明距离

今天分享双周赛的第三题,有关知识点是并查集。说来惭愧,之前刚整理过并查集的相关知识,做了些题目练练手,周赛的时候还是没有往这上面想,总是想着去匹配字符串。下面来整理下这道题目

  • 题目

给你两个整数数组 source 和 target ,长度都是 n 。还有一个数组 allowedSwaps ,其中每个 allowedSwaps[i] = [ai, bi] 表示你可以交换数组 source 中下标为 ai 和 bi(下标从 0 开始)的两个元素。注意,你可以按 任意 顺序 多次 交换一对特定下标指向的元素。

相同长度的两个数组 source 和 target 间的 汉明距离 是元素不同的下标数量。形式上,其值等于满足 source[i] != target[i] (下标从 0 开始)的下标 i(0 <= i <= n-1)的数量。

在对数组 source 执行 任意 数量的交换操作后,返回 source 和 target 间的 最小汉明距离 。

示例 1:

输入:source = [1,2,3,4], target = [2,1,4,5], allowedSwaps = [[0,1],[2,3]]
输出:1
解释:source 可以按下述方式转换:
- 交换下标 0 和 1 指向的元素:source = [2,1,3,4]
- 交换下标 2 和 3 指向的元素:source = [2,1,4,3]
source 和 target 间的汉明距离是 1 ,二者有 1 处元素不同,在下标 3 。

示例 2:

输入:source = [1,2,3,4], target = [1,3,2,4], allowedSwaps = []
输出:2
解释:不能对 source 执行交换操作。
source 和 target 间的汉明距离是 2 ,二者有 2 处元素不同,在下标 1 和下标 2 。

示例 3:

输入:source = [5,1,2,4,3], target = [1,5,4,2,3], allowedSwaps = [[0,4],[4,2],[1,3],[1,4]]
输出:0
  • 解释

汉明距离可以这样理解:对应位置元素不同则汉明距离加1

根据题意我们可以了解到,如果说0,1之间可以交换,1,3之间可以交换,那么0,3之间也是可以交换的。

因此,我们可以用并查集来维护这个联通块,对于source数组中任意两位置i,j,如果i,j在同一个联通分支里,那么i,j之间是可以互相交换的。不同联通块之间是没有任何联系。

对于任意的联通分支k,由于他们内部的位置可以任意交换,因此他们在source中的顺序并不重要,我们只需要对source数组中每个位置的数进行查询,看他们属于哪个集合并计数。

最后我们在遍历target数组,对每个位置的数,查看对应的集合,看是否存在,记录数量并更新计数

  • 遍历allowedSwaps数组中的所有元素,从而构建数组中位置的联通关系

  • 然后使用哈希表映射数组 target 中的每个元素和其位置,以便后续查找数组 source 中的元素在数组 target 中的位置

  • 代码

class Solution {
public:
    vector<int> p;
    int find(int x) {
        if (p[x] != x) {
            p[x] = find(p[x]);
        }
        return p[x];
    }
    int minimumHammingDistance(vector<int>& source, vector<int>& target, vector<vector<int>>& allowedSwaps) {
        int n = source.size();
        for (int i = 0;i < n; i++) p.push_back(i);
        //集合合并,可以交换的元素所在的联通块可以合并
        for (auto& t : allowedSwaps) {
            p[find(t[0])] = find(t[1]);
        }
        //把source里每个联通块的所有元素放到每个联通块对应的哈希表里
        vector<unordered_multiset<int>> h(n);
        //枚举source里的所有元素
        for (int i = 0;i < n; i++) {
            h[find(i)].insert(source[i]);
        }
        int res = 0;
        for (int i = 0;i < n; i++) {
            //target里对应点所在联通块的哈希表
            auto &t = h[find(i)];
            //如果此哈希表存在target[i],说明这个元素可以交换到
            if (t.count(target[i])) {
                t.erase(t.find(target[i]));
            }else {
                res++;
            }
        }
        return res;
    }
};
posted @ 2021-01-10 16:29  阿-栋  阅读(121)  评论(0编辑  收藏  举报