并查集通用类

  1. private class UnionFind{
  2. public int[] parent;
  3. public int[] rank;
  4. public int setcount;
  5. public UnionFind(int n) {
  6. this.parent = new int[n];
  7. this.rank = new int[n];
  8. for(int i=0;i<n;i++){
  9. parent[i] = i;
  10. rank[i] = 1;
  11. }
  12. this.setcount = n;
  13. }
  14. public void union(int x,int y){
  15. int rootx = find(x);
  16. int rooty = find(y);
  17. if(rootx==rooty) return;
  18. if(rank[rootx]==rank[rooty]){
  19. parent[rootx] = rooty;
  20. rank[rooty]++;
  21. }else if(rank[rootx]<rank[rooty]){
  22. parent[rootx] = rooty;
  23. }else {
  24. parent[rooty] = rootx;
  25. }
  26. this.setcount--;
  27. }
  28. public int find(int y) {
  29. if(y!=parent[y]){
  30. parent[y] = find(parent[y]);
  31. }
  32. return parent[y];
  33. }
  34. }

Leetcode 1722.执行交换操作后到最小汉明距离

1. 思路

思路就是将sources中的点看做是图中的节点,allowedSwaps数组表示各节点之间的连接关系,然后使用UnionFind去查看这个图的连通关系,假设这个图有n个连通分量,每一个连通分量都有一个父节点,每个连通分量在sources数组中的对应值都在target中有相应的映射,需要将target中的这些值都存储起来,以便于计算汉明距离,考虑到可能有重复的元素,故使用hashMap,key是target中的对应值,value是该值在集合中的个数,然后由前面说的,这个集合对应一个连通分量的根节点,因此需要将n个结点与对应的集合映射起来,这里又用到了一个hashMap。综上所述,需要用到两层hashMap。
最后,遍历sources数组中的每个元素,先用unionFind找出根节点,然后在上述的map中看看是否有值相等的target,若有,将这个target的数量减一;若无,汉明距离加一。遍历完sources数组后返回结果即可。

2. 代码

class Solution {
public int minimumHammingDistance(int[] source, int[] target, int[][] allowedSwaps) {
        int len = source.length;
        UnionFind uf = new UnionFind(len);
        for(int[] edge:allowedSwaps){
            uf.union(edge[0],edge[1]);
        }
        //HashMap<Integer, List<Integer>> hashMap = new HashMap<>();
        int res = 0;
        Map<Integer, Map<Integer, Integer>> map = new HashMap<>();
        for(int i = 0; i < target.length; i++) {
            int f = uf.find(i);
            if(!map.containsKey(f)) {
                map.put(f, new HashMap<>());
            }
            map.get(f).put(target[i], map.get(f).getOrDefault(target[i], 0)+1);
        }
        for(int i = 0; i < source.length; i++) {
            int f = uf.find(i);
            if(!map.get(f).containsKey(source[i]) || map.get(f).get(source[i]) == 0) {
                res++;
            }else {
                map.get(f).put(source[i], map.get(f).get(source[i])-1);
            }
        }
        return res;
    }
    //并查集通用类
   public int[] parent;
        public int[] rank;
        public int setcount;
        public UnionFind(int n) {
            this.parent = new int[n];
            this.rank = new int[n];
            for(int i=0;i<n;i++){
                parent[i] = i;
                rank[i] = 1;
            }
            this.setcount = n;
        }
        public void union(int x,int y){
            int rootx = find(x);
            int rooty = find(y);
            if(rootx==rooty) return;
            if(rank[rootx]==rank[rooty]){
                parent[rootx] = rooty;
                rank[rooty]++;
            }else if(rank[rootx]<rank[rooty]){
                parent[rootx] = rooty;
            }else {
                parent[rooty] = rootx;
            }
            this.setcount--;
        }
        public int find(int y) {
        if(y!=parent[y]){
            parent[y] = find(parent[y]);
        }
        return parent[y];
   }
}

Leetcode 1202.交换字符串中的元素

1. 思路

第 1 步:先遍历 pairs 中的索引对,将索引对中成对的索引输入并查集,并查集会帮助我们实现同属于一个连通分量中的元素的合并工作。注意:并查集管理的是「索引」不是「字符」。
第 2 步:遍历输入字符串 s,对于每一个索引,找到这个索引在并查集中的代表元,把同属于一个代表元的字符放在一起。这一步需要建立一个映射关系。键:并查集中的代表元,值:同属于一个代表元的 s 中的字符。可以使用哈希表建立映射关系。

2. 代码

class Solution {
    public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
        if(pairs.size()==0){
            return s;
        }
        int len = s.length();
        UnionFind unionFind = new UnionFind(len);
        for(List<Integer> pair:pairs){
            unionFind.union(pair.get(0),pair.get(1));
        }
        char[] charArray = s.toCharArray();
        HashMap<Integer, PriorityQueue<Character>> hashMap = new HashMap<>();
        for(int i=0;i<len;i++){
            int root = unionFind.find(i);
            hashMap.computeIfAbsent(root,key->new PriorityQueue<>()).offer(charArray[i]);
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            int root = unionFind.find(i);
            stringBuilder.append(hashMap.get(root).poll());
        }
        return stringBuilder.toString();
    }
    private class UnionFind{
        private int[] parent;
        private int[] rank;
        public UnionFind(int n){
            this.parent = new int[n];
            this.rank = new int[n];
            for(int i=0;i<n;i++){
                this.parent[i] = i;
                this.rank[i] = 1;
            }
        }
        public void union(int x,int y){
            int rootx = find(x);
            int rooty = find(y);
            if(rootx==rooty) return;
            if(rank[rootx]==rank[rooty]){
                parent[rootx] = rooty;
                rank[rooty]++;
            }
            else if(rank[rootx]<rank[rooty]){
                parent[rootx] = rooty;
            }else {
                parent[rooty] = rootx;
            }
        }
        public int find(int x){
            if(x!=parent[x]){
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }
    }
}