You are given a string s, and an array of pairs of indices in the string pairs where pairs[i] = [a, b] indicates 2 indices(0-indexed) of the string.

You can swap the characters at any pair of indices in the given pairs any number of times.

Return the lexicographically smallest string that s can be changed to after using the swaps.

给出一个字符串 给出一系列的允许调换的pair(index1, index2)表示这两个index可以互相之间调换 调换的次数不限 只要每次都从pair里面去选择就行了。
返回调换之后能得出来的最小的字典序。

idea:
不知道这个问题是一个用图去做的 我还在想是不是用链表去做这道题目。但是既然我知道这道题是用图做的 我首先想到到底是String s是一个图还是Pair是一个图。
仔细想了一下:应该是pair是一个图。因为pair中两者之间可以互换,所以针对这两个节点 或者说所有的可以互换的节点 我们都能通过某种方式进行互换(只要他们存在于同一个图上面 相互之间互相连通就能任意互换)
所以我在想 我们把在一个图里面的节点找出来 排出其最小的字典序 然后放回去,然后再把第二个图的节点进行排序然后再放回去…一直到没有图。
所以我感觉这个东西跟并查集有点关系。
首先先不想这个并查集到底是怎么实现的,先想一下我们需要储存值(abc)还是说储存index?我个人倾向于储存index 因为可以通过index然后找到对应的值然后排序 然后再根据index填回去。
不过首先 我们先构建起来并查集再说。

试着写了写 思路还可以 但是不能AC 结果不对

class Solution {
    public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
        char[] cs = s.toCharArray();
        
        int m =  s.length();
        int[] uf = new int[m];
        
        for (List<Integer> pair: pairs) {
            uf[find(uf, pair.get(0))] = find(uf, pair.get(1));
        }
        //then how are we gonna to know how many graphs in that uf and what nodes that contains in there
        //because if two nodes are in the same graph, the uf[i] should be the same
        //and in the uf, if uf[i] = i and there is no other nodes that equals to this value(i)
        //so we check the uf, if uf[i] != i, that means it must be belongs to some graph which belongs to pairs and we need to get all the that uf[i] values and the i, the best way to contains that is hahsmap
        HashMap<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < m; i++) {
            if (uf[i] != i) {
                if (!map.containsKey(i)) {
                    map.put(i, new ArrayList<>());
                    map.get(i).add(uf[i]);
                } else {
                    map.get(i).add(i);
                }
            } //if they are the same, that means it might be in pair(as a root in uf) or not in pair at all
        }
        for (List<Integer> indexs: map.values()) {//for each of the values
            sortByLexi(cs, indexs); //we sort it
        }
        return String.valueOf(cs);
    }
    
    private void sortByLexi(char[] cs, List<Integer> indexs) {
        int m = indexs.size();
        char[] chars = new char[m];
        int i = 0;
        for (Integer index: indexs) {
            chars[i++] = cs[index];
        }
        Arrays.sort(chars);
        int j = 0;
        for (Integer index: indexs) {
            cs[index] = chars[j++];
        }
        
    }
    
    private int find(int[] uf, int x) {
        if (x != uf[x]) {
            uf[x] = find(uf, uf[x]);
        }
        return uf[x];
    }
}

and I checked the solution, and find out that my thought is right, that’s something never happen before.
although my words to explain is bad, let’s see how other problem describe this problem:

Sort the characters within each connected group.

这句言简意赅的话属实让我感到羞愧

后来又自己搞清楚了union find,又自己修改了一下代码 可算是通过了

class Solution {
    public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
        char[] cs = s.toCharArray();
        
        int m =  s.length();
        int[] uf = new int[m];
        
        for (int i = 0; i < m; i++) {
            uf[i] = i; //initialize it
        }
        
        for (List<Integer> pair: pairs) { //construct union find
            union(uf, pair.get(0), pair.get(1));
        }
        //then how are we gonna to know how many graphs in that uf and what nodes that contains in there
        //because if two nodes are in the same graph, the uf[i] should be the same
        //and in the uf, if uf[i] = i and there is no other nodes that equals to this value(i)
        //so we check the uf, if uf[i] != i, that means it must be belongs to some graph which belongs to pairs and we need to get all the that uf[i] values and the i, the best way to contains that is hahsmap
        HashMap<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < m; i++) {
            int root = find(uf, i);
            map.putIfAbsent(root, new ArrayList<>());
            map.get(root).add(i);
        }
        for (List<Integer> indexs: map.values()) {//for each of the values
            sortByLexi(cs, indexs); //we sort it
        }
        return String.valueOf(cs);
    }
    
    private void sortByLexi(char[] cs, List<Integer> indexs) {
        int m = indexs.size();
        char[] chars = new char[m];
        int i = 0;
        for (Integer index: indexs) {
            chars[i++] = cs[index];
        }
        Arrays.sort(chars);
        int j = 0;
        for (Integer index: indexs) {
            cs[index] = chars[j++];
        }
        
    }
    
    private void union(int[] uf, int a, int b) {
        int aParent = find(uf, a);
        int bParent = find(uf, b);
        if (aParent < bParent) {
            uf[bParent] = aParent;
        } else {
            uf[aParent] = bParent;
        }
    }
    private int find(int[] uf, int x) {
        if (x != uf[x]) {
            uf[x] = find(uf, uf[x]);
        }
        return uf[x];                                                                                              
    }
}

但是通过对其他人代码的研究 发现自己还是太过于死板。
首先 对于对一个数组某些部分进行重排序然后再填回去 想的属实太过于死板 就像把这些要排的index汇总起来 然后单独开一个函数sortByLexi负责排序以及重新填回去的工作。

但是实际上,我们的map可以搞成 HashMap<Integer, PriorityQueue>的形式 然后最后只需要这样操作就可以了:

StringBuilder sb = new StringBuilder();
        for (int i = 0; i < sChar.length; i++) {
            sb.append(map.get(find(i)).poll());
        }
        return sb.toString();

这样操作简直不要太简洁,之前自己的方法就是狗屎。就是过于i集中精力实现想法 而忽视了其他可能的办法了。(不过话说回来 能实现也算是比较好了 但是明显不够)