leetcode
leetcode 2851 ~ 2900
婴儿名字

婴儿名字

难度:

标签:

题目描述

Each year, the government releases a list of the 10000 most common baby names and their frequencies (the number of babies with that name). The only problem with this is that some names have multiple spellings. For example,"John" and ''Jon" are essentially the same name but would be listed separately in the list. Given two lists, one of names/frequencies and the other of pairs of equivalent names, write an algorithm to print a new list of the true frequency of each name. Note that if John and Jon are synonyms, and Jon and Johnny are synonyms, then John and Johnny are synonyms. (It is both transitive and symmetric.) In the final list, choose the name that are lexicographically smallest as the "real" name.

Example:

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

Note:

  • names.length <= 100000

代码结果

运行时间: 132 ms, 内存: 19.5 MB


解释

方法:

此题解采用了并查集的数据结构来处理名字的等价关系。首先,通过处理synonyms列表来构建一个等价关系图,将具有相同含义的名字进行合并。合并规则是,总是让字典序较小的名字作为代表。接着,通过遍历names列表,将每个名字的频率累加到其根节点(即代表名字)上。最后,输出所有有频率记录的根节点及其对应的频率。这种方法有效地将所有同义名字归并到一个名字上,并且处理了名字间的传递性等价关系。

时间复杂度:

O((A + B) * α(N))

空间复杂度:

O(N)

代码细节讲解

🦆
在并查集中,如何确保总是将字典序较小的名字作为代表名字?具体的合并逻辑是怎样实现的?
在并查集的实现中,每次合并两个集合时,会先找到两个名字的根节点。接着,比较这两个根节点的字典序,将字典序较大的名字的根节点指向字典序较小的名字的根节点。这样,每个集合的代表(根节点)总是字典序最小的名字。具体逻辑是:1) 通过递归或迭代找到每个名字的根节点;2) 比较两个根节点的字典序;3) 更新较大字典序名字的根节点指针,指向较小字典序名字的根节点。这种做法确保了合并后的根节点总是最小字典序的名字,保持了集合的有序性。
🦆
并查集在合并过程中,如果遇到名字的链条很长,如何优化以提高查找根节点的效率?
在并查集中,为了优化长链条问题,可以使用两种主要的技术:路径压缩和按秩合并。路径压缩是在查找根节点的过程中,将查找路径上的每个节点直接连接到根节点,从而减少后续查找时间。按秩合并是根据每个节点的秩(通常是树的高度或大小)来决定合并方向,一般将秩较小的根节点指向秩较大的根节点,这样可以避免树过度增长。通过这两种技术,可以显著减少查找根节点的平均时间复杂度,使得并查集操作更加高效。
🦆
在处理名字的频率时,频率映射表是如何确保合并后只有根节点存储最终频率的?
在处理名字频率时,首先将每个名字的频率加到其对应的根节点上。具体操作是:1) 对于每个名字,通过并查集找到其根节点;2) 将名字的频率累加到根节点的频率上。这样,即使多个名字因为同义关系合并到一起,它们的频率也会被正确地加到同一个根节点上。最终,频率映射表中只记录每个根节点的总频率,而非合并前的各个名字的频率。这样可以确保输出的是合并后的名字及其总频率。

相关问题