给你一个字符串
s
,以及该字符串中的一些「索引对」数组pairs
,其中pairs[i] = [a, b]
表示字符串中的两个索引(编号从0
开始)。 你可以 任意多次交换 在pairs
中任意一对索引处的字符。 返回在经过若干次交换后,s
可以变成的按字典序最小的字符串。
输入:
s = "dcab"
,pairs = [[0,3],[1,2]]
输出:"bacd"
解释: 交换s[0]
和s[3]
,s = "bcad"
交换s[1]
和s[2]
,s = "bacd"
UnionFind
解决,pairs
的所有二元组可以看作连接,把s
中的下标连在一块,经典连通块问题
我们把可以交换的下标放在一个集合,这个集合内部,把所有字符排序,把最小的放在前面,这样就得到了最小的字典序
class Solution {
public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
char[] str = s.toCharArray();
int n = str.length;
UnionFind uf = new UnionFind(n);
for (List<Integer> list : pairs) {
int idx1 = list.get(0);
int idx2 = list.get(1);
uf.union(idx1, idx2);
}
/**
* 一个集合的字符,按照ASCII码排序,
* key是代表元
*
*/
/*
* Map<Integer, PriorityQueue<Character>> map = new HashMap<>();
* for(int i = 0; i < n; i++) {
* int f = uf.find(i);
* if(map.containsKey(f)) {//存在
* map.get(f).offer(str[i]);
* } else {
* PriorityQueue<Character> minHeap = new PriorityQueue<>();
* minHeap.offer(str[i]);
* map.put(f, minHeap);
* }
* }
*/
/**
* 使用数组优化
*/
int[][] map = new int[n][26];
for (int i = 0; i < n; i++) {
int f = uf.find(i);
map[f][str[i] - 'a']++;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
int f = uf.find(i);
int idx = -1;
while (map[f][++idx] == 0)
;// 第一个不为0的字符,就是ASCII最小的
sb.append((char) (idx + 'a'));
map[f][idx]--;
}
return sb.toString();
}
}
class UnionFind {
int[] parent;
int[] rank;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 1;
}
}
public int find(int x) {
while (x != parent[x]) {
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public void union(int i, int j) {
int f1 = find(i);
int f2 = find(j);
if (f1 != f2) {
if (rank[f1] == rank[f2]) {
parent[f2] = f1;
rank[f1]++;
} else if (rank[f1] < rank[f2]) {
parent[f1] = f2;
} else {
parent[f2] = f1;
}
}
}
}
本文由 mdnice 多平台发布