「这是我参与2022首次更文挑战的第37天,活动详情查看:2022首次更文挑战」
题目介绍
原题目请见上方链接
解题思路
在此题中,根据题目意思归纳以下条件:
- 每个数组的第一个元素是人的名称,从第二个元素开始是这个人的邮箱
- 邮箱是唯一的,同一个邮箱必定属于同一个人
- 人的名称不是唯一的,同一个名称不一定属于同一个人
要求:
- 合并账户,有邮箱交集的两个账户必定是属于同一个人,需要将同一个人的所有账户进行合并
- 合并账户之后,邮箱需要按照 字符 ASCII 顺序排列
我们要做的就是将同一个账户的所有邮箱进行合并去重,然后再跟对应的账户名称对应起来,就是一个账户
解题步骤
- 定义一个哈希表
emailIndexMap
,用于缓存每个邮箱与编号之间的映射,并且对邮箱去重 - 定义一个哈希表
emailNameMap
,用于缓存每个邮箱与账户名之间的映射,这是1对1
的关系 - 遍历账户列表
accounts
,将每个账户的账户名称和后面的邮箱列表分开 - 遍历邮箱列表,将邮箱与编号之间的映射关系缓存到
emailIndexMap
中,同时将邮箱与账户名称之间的映射关系缓存到emailNameMap
中
至此,我们将题目中的数据形成了如下的两个映射关系表
- 再次遍历账户列表
accounts
,将属于同一个账户的邮箱编号进行连通,每个集合中的邮箱均属于同一个账户 - 定义一个哈希表
accountIndexMap
,用于将邮箱按集合分离
- 然后将每个集合中的邮箱按 字符 ASCII 顺序排序
- 最后根据集合中的邮箱在
emailNameMap
中找到对应的账户名称,往每个集合的头部插入账户名称 - 返回合并后的账户列表
解题代码
var accountsMerge = function(accounts) {
const emailIndexMap = new Map()
const emailNameMap = new Map()
let index = 0
for (const account of accounts) {
const [name, ...accts] = account
for (const acct of accts) {
if (!emailIndexMap.has(acct)) {
// 缓存邮箱与编号之间的映射关系
emailIndexMap.set(acct, index++)
// 缓存邮箱与账户名称之间的映射关系
emailNameMap.set(acct, name)
}
}
}
const unionSet = new UnionSet(emailIndexMap.size)
for (const account of accounts) {
const [name, ...accts] = account
for (let i = 1; i < accts.length; i++) {
// 将同一账户的邮箱编号进行连通
unionSet.merge(emailIndexMap.get(accts[i - 1]), emailIndexMap.get(accts[i]))
}
}
const accountIndexMap = new Map()
// 将邮箱按集合进行分类
for (const [email, index] of emailIndexMap) {
const rootIndex = unionSet.get(index)
if (!accountIndexMap.has(rootIndex)) accountIndexMap.set(rootIndex, [])
accountIndexMap.get(rootIndex).push(email)
}
const res = []
for (const arr of accountIndexMap.values()) {
// 将邮箱按字符 ASCII 码排序
arr.sort()
// 往邮箱头部插入根据集合中的邮箱查找到的账户名称
arr.unshift(emailNameMap.get(arr[0]))
// 将当前账户插入到合并之后的账户列表中
res.push(arr)
}
// 返回合并后的账户列表
return res
};
// 并查集
class UnionSet {
constructor(n) {
this.fa = []
this.size = []
for (let i = 0; i < n; i++) {
this.fa[i] = i
this.size[i] = 1
}
}
get(v) {
if (this.fa[v] === v) return v
const root = this.get(this.fa[v])
this.fa[v] = root
return root
}
merge(a, b) {
const ra = this.get(a), rb = this.get(b)
if (ra === rb) return
if (this.size[ra] < this.size[rb]) {
this.fa[ra] = rb
this.size[rb] += this.size[ra]
} else {
this.fa[rb] = ra
this.size[ra] += this.size[rb]
}
}
}
复制代码