题目描述
给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。

你可以 任意多次交换 在 pairs 中任意一对索引处的字符。
返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。

示例 1:
输入:s = "dcab", pairs = [[0,3],[1,2]]
输出:"bacd"
解释:
交换 s[0] 和 s[3], s = "bcad"
交换 s[1] 和 s[2], s = "bacd"
示例 2:
输入:s = "dcab", pairs = [[0,3],[1,2],[0,2]]
输出:"abcd"
解释:
交换 s[0] 和 s[3], s = "bcad"
交换 s[0] 和 s[2], s = "acbd"
交换 s[1] 和 s[2], s = "abcd"
示例 3:
输入:s = "cba", pairs = [[0,1],[1,2]]
输出:"abc"
解释:
交换 s[0] 和 s[1], s = "bca"
交换 s[1] 和 s[2], s = "bac"
交换 s[0] 和 s[1], s = "abc"

解题思路
该题需要回炉,看题解才能理解
考察并查集--将可以间接连通的字母并为一个集合,然后将其按升序排列。这样便可以实现整体的字典序升序(因为子连通内可任意交换,可以达到最后升序)
运行结果
图片说明
java代码参考题解

class Solution {
    public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
        //初始化连通图
        DisjointSetUnion dsu = new DisjointSetUnion(s.length());
        for(List<Integer> pair:pairs){
            //合并
            dsu.unionSet(pair.get(0),pair.get(1));
        }
        //使用map存储祖先节点到子节点列表的映射,存储并查集结果
        //例如s = "dcab", pairs = [[0,3],[1,2]]
        //0:[d,b]  1:[c,a]
        Map<Integer,List<Character>> map =new HashMap<Integer,List<Character>>();
        for(int i =0;i<s.length();i++){
            int parent = dsu.find(i);//找到该节点的父节点
            if(!map.containsKey(parent)){
                map.put(parent,new ArrayList<Character>());
            }
            map.get(parent).add(s.charAt(i));
        }//将同意祖先节点下的子节点放在一起
        //对map中的值进行排序=降序
        for(Map.Entry<Integer,List<Character>> entry:map.entrySet()){
            Collections.sort(entry.getValue(),new Comparator<Character>(){
                public int compare(Character c1,Character c2){
                    return c2-c1;
                }
            });
        }
        StringBuffer sb = new StringBuffer();
        for(int i =0;i<s.length();i++){
            int x = dsu.find(i);
            List<Character> list =map.get(x);
            sb.append(list.remove(list.size()-1));
        }//从头到尾,每次放入子连通中的较小的那个
        return sb.toString();

    }
}

//定义并差集类
class DisjointSetUnion{
    int n;  //并查集长度
    int[] rank;  //节点等级
    int[] f;   //存储对应的祖先节点

    //构造函数,初始化属性
    public DisjointSetUnion(int n){
        this.n = n;
        rank = new int[n];
        Arrays.fill(rank,1);
        f = new int[n];
        for(int i=0;i<n;i++){
            f[i] = i;
        }
    }

    //方法find,寻找给节点的祖先
    public int find(int x){
        return f[x] == x?x:(f[x]=find(f[x]));
    }

    //合并到一个图***同有一个祖先
    public void unionSet(int x, int y) {
        int fx=find(x),fy = find(y);
        if(fx==fy){
            return;
        }
        if(rank[fx]<rank[fy]){
            //swap(fx,fy);
            int temp = fx;
            fx=fy;
            fy=temp;
        }
        //fx级别高,要作为祖先
        rank[fx] +=rank[fy];
        f[fy] = fx;
    }
}