这道题太麻烦了,并查集,还是用之前的模版,但是这题的主要解体思路,按照助教写的太麻烦了,并且中间有的看不懂,看其他人的解释有的代码挺少的,但是也没有注释,更看不懂了,主要是别人写的并查集和助教写的这个并查集模版不一样,前几题我还说并查集设计的解体逻辑并不麻烦,这直接给来了一个这..
/**
* @param {string} s
* @param {number[][]} pairs
* @return {string}
*/
var smallestStringWithSwaps = function (s, pairs) {
let len = s.length;
let uf = new UnionFind(len);
// 1. 将可以进行交换的字符进行连通
for (let i = 0; i < pairs.length; i++) {// 先拿到索引对,遍历数组
let index1 = pairs[i][0], index2 = pairs[i][1];// 拿到里面的每一对数组
if (uf.findSet(index1) !== uf.findSet(index2)) {// 拿到两个索引,进行连通
uf.unite(index1, index2);
}
}
// 2.先拿到连通后的数组
let fa = uf.parent;
// 将连通的字符存入到一个新的数组里面进行排序
let vec = new Array(len).fill(0).map(() => new Array()); // 根据祖先节点进行分组,value是字符串里面的字符的结合
// 这一步看是不明白了
for (let i = 0; i < len; i++) {
fa[i] = uf.findSet(i);
vec[fa[i]].push(s[i]);
}
for (let i = 0; i < len; i++) {
if (vec[i].length > 0) {
vec[i].sort((a, b) => a.charCodeAt() - b.charCodeAt());
}
}
// 通过原始字符坐标,获取字符的组号,拼接字符串
// 记录每一组字符串位置
let p = new Array(len).fill(0);
// 输出字符的数组
let ans = [];
for (let i = 0; i < len; i++) {
ans.push('1');
}
// 通过原始字符坐标,获取字符的组号,拼接字符串
for (let i = 0; i < len; i++) {
ans[i] = vec[fa[i]][p[fa[i]]];
p[fa[i]]++;
}
// 拼接字符jion
return ans.join('');
};
// 并查集的模板
class UnionFind {
constructor(n) {
this.parent = new Array(n).fill(0).map((v, i) => i);
this.rank = new Array(n).fill(1);
this.setCount = n; // 连通分量
}
findSet (index) {
if (this.parent[index] !== index) {
this.parent[index] = this.findSet(this.parent[index]);
}
return this.parent[index];
}
unite (index1, index2) { // 合并
// 拿到他们的顶点坐标
let root1 = this.findSet(index1), root2 = this.findSet(index2);
if (root1 !== root2) {
// 判断一下各自集合的节点个数,节点少的集合要往节点多的集合上合并
if (root1 < root2) {
[root1, root2] = [root2, root1]; // root1 是节点个数多的集合
}
// 合并根节点
this.parent[root2] = root1;
// 计算已经合并的节点数量
this.rank[index1] += this.root2;
this.setCount--; // 合并一个,城市数量减去一
}
}
getCount () {
return this.setCount;
}
connected (index1, index2) { // 来判断两个顶点,是否是一个连通分量
let root1 = this.findSet(index1), root2 = this.findSet(index2);
return root1 === root2;
}
}