[路飞]_js算法:leetcode 1202-交换字符串中的元素

117 阅读1分钟

leetcode 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"

示例 2:

输入: s = "dcab", pairs = [[0,3],[1,2],[0,2]]
输出: "abcd"
解释:
交换 s[0] 和 s[3], s = "bcad"
交换 s[0] 和 s[2], s = "acbd"
交换 s[1] 和 s[2], s = "abcd"

示例 3:

输入: s = "cba", pairs = [[0,1],[1,2]]
输出: "abc"
解释:
交换 s[0] 和 s[1], s = "bca"
交换 s[1] 和 s[2], s = "bac"
交换 s[0] 和 s[1], s = "abc"

思路: 采用并查集+小顶堆

/**
 * @param {string} s
 * @param {number[][]} pairs
 * @return {string}
 */
var smallestStringWithSwaps = function(s, pairs) {
    let union=new unionSet(s.length);
    for(let i=0;i<pairs.length;i++){
        union.merge(pairs[i][0],pairs[i][1])
    }
    let h=new Array(s.length).fill(0).map(item=>{
       return new Heap((a,b)=> a.charCodeAt()-'0'<b.charCodeAt()-'0')
    })
  
    for(let i=0;i<s.length;i++){
        h[union.find(i)].push(s[i])

    }
    let temp='';
    for(let i=0;i<s.length;i++){
        temp+=h[union.find(i)].top;
        h[union.find(i)].pop()
    }
    return temp

};
// 并查集
class unionSet {
    constructor(n){
        this.node=new Array(n).fill(0).map((item,index)=>index)
    }
    find(x){
        return this.node[x]=(x==this.node[x]?x:this.find(this.node[x]))
    }
    merge(a,b){
        let fa=this.find(a),fb=this.find(b);
        this.node[fa]=fb;
        return;
    }
}
//堆得实现
class Heap {
  constructor(cmp) {
      this.data = [];
      this.cmp = cmp;
  }
  get size() {
      return this.data.length;
  }
  get top() {
      return this.data[0];
  }
  getData() {
      return this.data;
  }
  swap(i, j) {
      [this.data[i], this.data[j]] = [this.data[j], this.data[i]];
  }
  // 向上冒泡
  up(i) {
      let index=this.data.length-1;
      while(index>0){
          let p=Math.floor((index-1)/2);
          if(p>=0&&this.cmp(this.data[index],this.data[p])){
              this.swap(index,p);
              index=p;
          }else{
              break;
          }
      }
  }
  // 下沉操作
  down(i) {
    if(this.data.length<2)return;
    let index=0,l=2*index+1,len=this.data.length;
    while(l<len){
      let r=l+1;
      if(r<len&&this.cmp(this.data[r], this.data[l]))l=r;
      if(this.cmp(this.data[index], this.data[l]))break;
      this.swap(index,l)
      index=l;
      l=index*2+1;
    }
  }
  push(item) {
    this.data.push(item);
    this.up();
  }
  //删除堆顶元素
  pop() {
      this.swap(0, this.data.length - 1);
      const res = this.data.pop();//已删除的元素(原来的堆顶元素)
      this.down();
      return res;
  }
}