[路飞]_交换字符串中的元素

225 阅读2分钟

1202. 交换字符串中的元素

题目

给你一个字符串 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('')
}