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

762 阅读1分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

看一百遍美女,美女也不一定是你的。但你刷一百遍算法,知识就是你的了~~

谁能九层台,不用累土起!

题目地址

题目

给你一个字符串 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"

提示:

  • 1 <= s.length <= 10^5
  • 0 <= pairs.length <= 10^5
  • 0 <= pairs[i][0], pairs[i][1] < s.length
  • s 中只含有小写英文字母

解题思路

  • 这题考察的知识点比较多
  • 我们用并查集找出可以相互之间随意替换的元素
  • map对象来记录可以随意替换的元素
  • 将可以替换的元素排序
  • 定义一个用于记录返回值的str,遍历s
  • 找出s每一项可以用来替换的最'小'的字母将其填充到str

解题代码

var smallestStringWithSwaps = function(s, pairs) {
    if(!pairs.length) return s
    const union = new UnionFind(s.length)
    for(let [x,y] of pairs){
        union.merge(x,y)
    }
    const map = {}
    for(let i = 0;i<s.length;i++ ){
        const parent = union.find(i)
        if(!map[parent]) map[parent] = []
        map[parent].push(s[i])
    }
    for(let i in map){
        map[i].sort((a,b)=> b.charCodeAt(0) - a.charCodeAt(0))
    }
    let str = ''
    for(let i=0;i<s.length;i++){
        const parent = union.find(i)
        str += map[parent].pop()
    }
    return str

};

class UnionFind {
    constructor(len){
        this.parents = new Array(len).fill(0).map((v,i)=>i)
        this.rank =  new Array(len).fill(0)
    }
    find(i){
        if(this.parents[i] == i ) return i
        return this.find(this.parents[i])
    }
    connect(a,b){
        return this.find(a) == this.find(b)
    }
    merge(a,b){
        if(this.connect(a,b)) return
        this.parents[this.find(a)] = this.find(b)
    }
}

跑一下代码,我们发现超时了。

image.png

怎么办呢,我们优化一下merge逻辑,每次将数量少的节点指向数量多的节点,详细代码如下:

merge(a,b){
    if(this.connect(a,b)) return
    const fa = this.find(a)
    const fb = this.find(b)
    if(this.rank[fa]>this.rank[fb]){
        this.parents[fb] = fa
    }else{
        this.parents[fa] = fb
        if(this.rank[fa]==this.rank[fb] ){
            this.rank[fb]++
        }
    }
}

如有任何问题或建议,欢迎留言讨论!