题目
给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。
你可以 任意多次交换 在 pairs 中任意一对索引处的字符。
返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。
示例1
输入:s = "dcab", pairs = [[0,3],[1,2]]
输出:"bacd"
解释:
交换 s[0] 和 s[3], s = "bcad"
交换 s[1] 和 s[2], s = "bacd"
题解
并查集
- 理解本思路需要理解并查集,什么是并查集?关闭窗口,打开谷歌;哈哈
- 理解了并查集后在理解一个概念,并查集内的字符串可以被交换到任意位置
- 理解完上述连个概念可以用并查集解决本题了
- 第1步枚举pairs数组,将相连的字符串下标放在并查集中
- 第2步,枚举字符串s,根据字符串所在的下标,在并查集找到字符串下标【注意,是下标】的公共祖先
- 第3步,将第2步的数据放入到map中,map的数据类型是{'下标key':[下标1,下标2],'字符串key':[字符串1,字符串2]}
- 第4步,因为在相同集合内的字符串可以被交换到任意位置,所以,第3步的map数据可以通过字典排序得到最小字典字符窜
- 第5部,枚举map将map数据重新构建成字符串
- 代码如下
代码
class Union {
constructor(n) {
this.list = Array(n)
.fill(0)
.map((v, i) => i)
}
find(x) {
if (x === this.list[x]) return x
const root = this.find(this.list[x])
this.list[x] = root
return root
}
merge(x, y) {
const rootX = this.find(x)
const rootY = this.find(y)
if (rootX === rootY) return
this.list[rootX] = rootY
}
}
var smallestStringWithSwaps = function (s, pairs) {
// 并查集
// 并查集内字符串可以任意替换位置
const len = pairs.length
const union = new Union(s.length)
for (let i = 0; i < len; i++) {
const [x, y] = pairs[i]
union.merge(x, y)
}
const map = new Map()
for (let i = 0; i < s.length; i++) {
const root = union.find(i)
if (map[root]) {
map[root].indexs.push(i)
map[root].strings.push(s[i])
} else {
map[root] = {
indexs: [i],
strings: [s[i]],
}
}
}
Object.keys(map).forEach((k) => {
map[k].indexs.sort((a, b) => a - b)
map[k].strings.sort()
})
const result = []
Object.keys(map).forEach((k) => {
const indexs = map[k].indexs
const strings = map[k].strings
for (let i = 0; i < indexs.length; i++) {
result[indexs[i]] = strings[i]
}
})
return result.join('')
}