1. 程式人生 > 實用技巧 >Leetcode5650. 執行交換操作後的最小漢明距離

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;
    }
};