题意
最近刷题刷到了一道关于字符串换位置的题目,采用的解法是合并集的方法,于是参考了优快云上的一篇文章,发现很容易理解。
题目
给你一个字符串 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”
从题目中可以理解到首先需要将pairs中相互影响的,相互联系的数字凑成一个大的集合,然后在这个集合中升序排序字符,然后再在各个位置上放置相应的字符,这里把这个大集合想想成一个大的帮派,同时这个帮派在不断的扩容变大,pairs集合数组中就是建立友好的协议的证明。
于是首先初始化每个人一个帮派,接着通过pairs将相互想要建交的帮派融合,融合后选择后面位置的为新帮派的老大,可以通过合并集实现如下
for(int i = 0; i < len; ++i) root[i] = i;
for(int i = 0; i < pairs.size(); ++i){
if(find(pairs.get(i).get(0))!=find(pairs.get(i).get(1))){
root[find(pairs.get(i).get(0))] = find(pairs.get(i).get(1));
};
}
其中find()函数为寻找自身老大的过程,
public int find(int son){
int temp = son;
while(son!=root[son]){
son = root[son];
}
while(root[temp]!=son){
root[temp] = son;
}
return son;
}
通过不断的判断自己的当前上司是不是总上司,然后再让自己直接服务于总上司。
在字符排序的过程使用单调优先队列,由小顶堆实现底层,可以直接取堆顶元素来放置相应于的位置,总的代码如下
int []root;
public String smallestStringWithSwaps(String s, List<List<Integer>> pairs) {
int len = s.length();
root = new int[len];
for(int i = 0; i < len; ++i) root[i] = i;
for(int i = 0; i < pairs.size(); ++i){
if(find(pairs.get(i).get(0))!=find(pairs.get(i).get(1))){
root[find(pairs.get(i).get(0))] = find(pairs.get(i).get(1));
};
}
Map<Integer, PriorityQueue<Character>> cache = new HashMap<>();
for(int i = 0; i < len; ++i){
cache.computeIfAbsent(find(i), k -> new PriorityQueue<Character>()).add(s.charAt(i));
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < len; ++i){
sb.append(cache.get(find(i)).poll());
}
return sb.toString();
}
public int find(int son){
int temp = son;
while(son!=root[son]){
son = root[son];
}
while(root[temp]!=son){
root[temp] = son;
}
return son;
}