LeetCode 算法:婴儿名字

56 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 24 天,点击查看活动详情

婴儿名字

原题地址

每年,政府都会公布一万个最常见的婴儿名字和它们出现的频率,也就是同名婴儿的数量。有些名字有多种拼法,例如,JohnJon 本质上是相同的名字,但被当成了两个名字公布出来。给定两个列表,一个是名字及对应的频率,另一个是本质相同的名字对。设计一个算法打印出每个真实名字的实际频率。注意,如果 JohnJon 是相同的,并且 JonJohnny 相同,则 JohnJohnny 也相同,即它们有传递和对称性。

在结果列表中,选择 字典序最小 的名字作为真实名字。

示例:

输入:names = ["John(15)","Jon(12)","Chris(13)","Kris(4)","Christopher(19)"],
synonyms = ["(Jon,John)","(John,Johnny)","(Chris,Kris)","(Chris,Christopher)"]
输出:["John(27)","Chris(36)"]

提示:

  • names.length <= 100000

思路分析

  1. 首先将 names 中的数据拆分存储到一个对象 nameMap 中,以名字为 key,人数为 value 值存储;
  2. 然后将 synonyms 中名字的本质找出来,此时我们定义一个 UnionSet 来存储本质名字,其中 data 表示本质名字的数据,size 表示其长度;
  3. UnionSet 中定义一个 find 方法来寻找最小字典序的名字,然后定义一个 union 方法,将最小字典序的名字和当前名字对应起来;
  4. 遍历 nameMap,若不在集合中,则单独处理,最后的数据即为当前的数据;若在集合中,则需要将对应的名字找出来然后求和得到最后的值,此值记为 resMap
  5. 最后返回结果为数组,因此遍历 resMap,将数据组装好存储到 res 中返回即可。

AC 代码

/**
 * @param {string[]} names
 * @param {string[]} synonyms
 * @return {string[]}
 */
var trulyMostPopular = function(names, synonyms) {
    const nameMap = {}
    const resMap = {}
    let synonymsSet = new UnionSet()
    const res = []

    names.forEach(item => {
        const strs = item.split('(')
        nameMap[strs[0]] = Number(strs[1].substring(0, strs[1].length - 1))
    })
    
    synonyms.forEach(item => {
        const sub = item.substring(1, item.length - 1).split(',')
        synonymsSet.union(sub[0], sub[1])
    })

    for (n in nameMap) {
        if (synonymsSet.data[n] === undefined){ // 不在并查集中的名字单独列出
            resMap[n] = nameMap[n]
            continue
        }
        let name = synonymsSet.find(n)
        if (resMap[name] == undefined) resMap[name] = nameMap[n]
        else resMap[name] += nameMap[n]
    }

    for (item in resMap) { //数组输出
        res.push(item + '(' + resMap[item] + ')')
    }

    return res
};

class UnionSet {
    constructor () {
        this.data = {};
        this.size = 0;
    }
    
    find (item) {
        while (this.data[item] != item) item = this.data[item]
        return item
    }
    
    union(a, b) {
        if (this.data[a] === undefined) {
            this.data[a] = a;
            this.size++;
        }

        if (this.data[b] === undefined) {
            this.data[b] = b;
            this.size++;
        } 

        const dataA = this.find(a)
        const dataB = this.find(b)
        if (dataA < dataB) this.data[dataB] = dataA
        else this.data[dataA] = dataB
    }
}

结果:

  • 执行结果: 通过
  • 执行用时:400 ms, 在所有 JavaScript 提交中击败了50.00%的用户
  • 内存消耗:69.8 MB, 在所有 JavaScript 提交中击败了66.67%的用户
  • 通过测试用例:36 / 36

END