题目描述
分析
数组的每项一个字数组,然后第一项是 name,第二项开始是 emails,题目要求把具有相同邮箱的账号合并起来,因此我想到的就是并查集
算法,数据结构
哈希表,并查集
解题思路
对于一个并查集,最关键的就是亮点,fa 里存的是什么以及怎么把联通关系和题目对应起来
并查集的意义
这里的 fa 存储的是邮箱编号的联通关系
在这里我给每个邮箱一个单独的编号,然后把邮箱和它的编号放到一个 map 里做对应,把邮箱和它的名字做对应,放到另一个 map
再次遍历账户,对于一个账户下的邮箱,连接他们!,根据这个联通关系我们继续向下走
构建账户
有了这个联通关系,能干什么呢?
实际上,此时已经可以构建合并后的所有账户了
我把所有联通的邮箱放到一个数组里,然后构建出一个单独的账户
这里要进行遍历的,实际上是所有的 email, 找到他在联通集里的 index, 做一个单独的数组,这个数组里会放所有和他联通的邮箱
最后,再把名字放进数组(根据题目),排序所有邮箱
代码
var accountsMerge = function (accounts) {
const emailToIndex = new Map()
const emailToName = new Map()
let emailsCount = 0
for (const account of accounts) {
const name = account[0] // email name
const size = account.length // name + email address length
for (let i = 1; i < size; i++) {
// iterate each email addr
const email = account[i] // email addr
if (!emailToIndex.has(email)) {
// map do not has this email recorded
emailToIndex.set(email, emailsCount++) // unique email address index++
emailToName.set(email, name) // assign an name to this email, each email has an unique name
}
}
}
const uf = new UnionFind(emailsCount)
for (const account of accounts) {
const firstEmail = account[1] // first email address in this account
const firstIndex = emailToIndex.get(firstEmail) // the name assigned to this email above
const size = account.length // items length of this account
for (let i = 2; i < size; i++) {
// iterate each email next to the first one in this account
const nextEmail = account[i]
const nextIndex = emailToIndex.get(nextEmail)
uf.union(firstIndex, nextIndex) // merge them all in union set
}
}
// how many accounts are there after merge
const indexToEmails = new Map()
for (const email of emailToIndex.keys()) {
// iterate each email address
const index = uf.find(emailToIndex.get(email)) // index of this email in DSU
const account = indexToEmails.get(index) ? indexToEmails.get(index) : [] // if has already record the index, if so, then extract this account
account.push(email)
indexToEmails.set(index, account)
}
const merged = []
for (const emails of indexToEmails.values()) {
emails.sort() // according to ASCII
const name = emailToName.get(emails[0])
const account = [] // make account
account.push(name)
account.push(...emails)
merged.push(account)
}
return merged
}
class UnionFind {
constructor(n) {
this.parent = new Array(n).fill(0).map((element, index) => index)
}
union(index1, index2) {
this.parent[this.find(index2)] = this.find(index1)
}
find(index) {
if (this.parent[index] !== index) {
this.parent[index] = this.find(this.parent[index])
}
return this.parent[index]
}
}