1. 程式人生 > 其它 >Leetcode並查集相關知識以及題目整理

Leetcode並查集相關知識以及題目整理

技術標籤:leetcode和機試題leetcode

1、執行交換操作後的最小漢明距離

題目:

給你兩個整數陣列 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

提示:

n == source.length == target.length
1 <= n <= 105
1 <= source[i], target[i] <= 105
0 <= allowedSwaps.length <= 105

allowedSwaps[i].length == 2
0 <= ai, bi <= n - 1
ai != bi

程式碼:

class Solution {
public:
int getf(vector<int>&f,int x){
    if(f[x]==x)return x;
    int nf=getf(f,f[x]);
    f[x]=nf;
    return nf;
}
void add(vector<int>&f ,int x,int y){
    int fx=getf(f,x);
    int fy=getf(f,y);
    f[fx]=fy;
}
    int minimumHammingDistance(vector<int>& source, vector<int>& target, vector<vector<int>>& allowedSwaps) {
        int n=source.size();
    vector<int> f(n);
    for(int i=0;i<n;i++){
        f[i]=i;
    }
    for(const auto& e:allowedSwaps){
        add(f,e[0],e[1]);
    }
    unordered_map<int,unordered_multiset<int>> s,t;
    for(int i=0;i<n;i++){
        int fa=getf(f,i);
        s[fa].insert(source[i]);
        t[fa].insert(target[i]);
    }
    int ret=0;
    for(int i=0;i<n;i++){
        if(s.find(i)==s.end())continue;
        for(int x:s[i]){
            if(t[i].find(x)==t[i].end()){
                ret++;
            }else{
                t[i].erase(t[i].find(x));
            }
        }
    }
    return ret;
    }
};

想法:

根據題意不難注意到,如果 1,2之間可以交換,2,3 之間可以交換,那麼即使 [1,3]未出現在allowedSwaps 陣列中,1,3之間也是可以交換的。因此,我們使用並查集來維護這一關係:對於 source 陣列中兩個任意的位置 i,j,如果 i,j在同一個聯通分支裡,那麼 i,j之間就是可以交換的。於是,需要首先遍歷allowedSwaps 陣列中所有元素,從而構建source 陣列中位置之間的聯通關係。對於任意的聯通分支 k,由於它們內部的位置之間可以任意交換,因此它們初始出現在 source 陣列中的順序並不重要。故我們為每個聯通分支 k 維護 source 中對應位置元素的集合,以及target 中對應位置元素的集合。隨後,漢明距離的最小值,就是這兩個集合之間不同的元素的數量。那麼兩個集合之間不同元素的數量呢?我們遍歷第一個集合中的每個元素:如果該元素出現在第二個集合中,就將該元素從第二個集合中刪除;否則,如果沒有出現,則將計數器加 1。值得注意的是,在本題中,我們需要允許集合中的元素出現重複。在下面的程式碼中,我們使用 C++ 中的 unordered_multiset 資料結構。

根據allowSwap陣列建立連通團,然後對source和target分別獲取對應的連通團,獲取以後進行對比,target連通團中最好包括source連同團的每個元素,如果不包括,那麼計數器+1.