GuilinDev

Lc1202

05 August 2008

1202. Smallest String With Swaps

给定一个字符串 s,以及字符串对中的索引对数组,其中对 [i] = [a, b] 表示字符串的 2 个索引(0 索引)。

可以多次交换给定对中任何一对索引处的字符。

返回使用交换后 s 可以更改为的字典最小字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Example 1:

Input: s = "dcab", pairs = [[0,3],[1,2]]
Output: "bacd"
Explaination: 
Swap s[0] and s[3], s = "bcad"
Swap s[1] and s[2], s = "bacd"

Example 2:

Input: s = "dcab", pairs = [[0,3],[1,2],[0,2]]
Output: "abcd"
Explaination: 
Swap s[0] and s[3], s = "bcad"
Swap s[0] and s[2], s = "acbd"
Swap s[1] and s[2], s = "abcd"

Example 3:

Input: s = "cba", pairs = [[0,1],[1,2]]
Output: "abc"
Explaination: 
Swap s[0] and s[1], s = "bca"
Swap s[1] and s[2], s = "bac"
Swap s[0] and s[1], s = "abc"

Union Find + HashMap + PriorityQueue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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) {
            int index1 = pair.get(0);
            int index2 = pair.get(1);
            unionFind.union(index1, index2);
        }

        char[] charArray = s.toCharArray();
        Map<Integer, PriorityQueue<Character>> hashMap = new HashMap<>(len);
        for (int i = 0; i < len; i++) {
            int root = unionFind.find(i);
            if (hashMap.containsKey(root)) {
                hashMap.get(root).offer(charArray[i]);
            } else {
                PriorityQueue<Character> minHeap = new PriorityQueue<>();
                minHeap.offer(charArray[i]);
                hashMap.put(root, minHeap);
            }

        }

        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])
                return x;
            return parent[x] = find(parent[x]);
        }
    }
}

Union Find + HashMap + Sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class Solution {
    
    public class UnionFind {
        private int[] roots;
        private int[] ranks;
        private int group;
        
        public UnionFind(int n) {
            roots = new int[n];
            ranks = new int[n];
            group = n;
            
            for(int i = 0; i < n; ++i) {
                roots[i] = i;
                ranks[i] = 1;
            }
        }
        
        public int find(int x) {
            if(x == roots[x])
                return x;
            return roots[x] = find(roots[x]);
        }
        
        public boolean union(int x, int y) {
            int rootx = find(x);
            int rooty = find(y);
            if(rootx != rooty) {
                if(ranks[rootx] > ranks[rooty]) {
                roots[rooty] = rootx;
                } else if(ranks[rootx] < ranks[rooty]) {
                    roots[rootx] = rooty;
                } else {
                    roots[rooty] = rootx;
                    ranks[rootx] += 1;
                }
                group--;
                return true;
            }
            return false;
        }
        
        public int getGroup() {
            return group;
        }
    }

    public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
        // group indices by union find
        int slen = s.length();
        UnionFind uf = new UnionFind(slen);
        for(List<Integer> pair : pairs) {
            uf.union(pair.get(0), pair.get(1));
        }
        
        // get indices of each group
        Map<Integer, List<Integer>> map = new HashMap<>();
        for(int i = 0; i < slen; ++i) {
            int root = uf.find(i);
            if(!map.containsKey(root))
                map.put(root, new ArrayList<>());
            map.get(root).add(i);
        }
        
        // get characters by the indices of each group, sort by the characters, 
        // then put the sorted characters back to new characters array by the indices.
        char[] newChars = new char[slen];
        for(Map.Entry<Integer, List<Integer>> e : map.entrySet()) {
            List<Integer> group = e.getValue();
            
            int glen = group.size();
            char[] gchars = new char[glen];
            for(int i = 0; i < glen; ++i)
                gchars[i] = s.charAt(group.get(i));
            
            Arrays.sort(gchars);
            for(int i = 0; i < glen; ++i)
                newChars[group.get(i)] = gchars[i];
        }
        
        return new String(newChars);
    }
}