zoukankan      html  css  js  c++  java
  • [Swift]LeetCode721. 账户合并 | Accounts Merge

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
    ➤微信公众号:山青咏芝(shanqingyongzhi)
    ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
    ➤GitHub地址:https://github.com/strengthen/LeetCode
    ➤原文地址: https://www.cnblogs.com/strengthen/p/10513271.html 
    ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
    ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

    Given a list accounts, each element accounts[i] is a list of strings, where the first element accounts[i][0] is a name, and the rest of the elements are emails representing emails of the account.

    Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.

    After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order.

    Example 1:

    Input: 
    accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]]
    Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'],  ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]]
    Explanation: 
    The first and third John's are the same person as they have the common email "johnsmith@mail.com".
    The second John and Mary are different people as none of their email addresses are used by other accounts.
    We could return these lists in any order, for example the answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'], 
    ['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted.

    Note:

    • The length of accounts will be in the range [1, 1000].
    • The length of accounts[i] will be in the range [1, 10].
    • The length of accounts[i][j] will be in the range [1, 30].

    给定一个列表 accounts,每个元素 accounts[i] 是一个字符串列表,其中第一个元素 accounts[i][0] 是 名称 (name),其余元素是 emails 表示该帐户的邮箱地址。

    现在,我们想合并这些帐户。如果两个帐户都有一些共同的邮件地址,则两个帐户必定属于同一个人。请注意,即使两个帐户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的帐户,但其所有帐户都具有相同的名称。

    合并帐户后,按以下格式返回帐户:每个帐户的第一个元素是名称,其余元素是按顺序排列的邮箱地址。accounts 本身可以以任意顺序返回。

    例子 1:

    Input: 
    accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]]
    Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'],  ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]]
    Explanation: 
      第一个和第三个 John 是同一个人,因为他们有共同的电子邮件 "johnsmith@mail.com"。 
      第二个 John 和 Mary 是不同的人,因为他们的电子邮件地址没有被其他帐户使用。
      我们可以以任何顺序返回这些列表,例如答案[['Mary','mary@mail.com'],['John','johnnybravo@mail.com'],
      ['John','john00@mail.com','john_newyork@mail.com','johnsmith@mail.com']]仍然会被接受。
    

    注意:

    • accounts的长度将在[1,1000]的范围内。
    • accounts[i]的长度将在[1,10]的范围内。
    • accounts[i][j]的长度将在[1,30]的范围内。

    552ms

      1 class Solution {
      2     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
      3         var dsu = DSU()
      4         for account in accounts {
      5             var emails = Array(account[1...])
      6             var name = account[0]
      7             dsu.addEdge(emails, name)
      8         }
      9         return dsu.unions()
     10     }
     11 }
     12 
     13 struct DSU {
     14     var mapping: [String: Int] = [:]
     15     var arr: [Int]
     16     var size: [Int]
     17     var comps: Int
     18     var names: [Int: String] = [:]
     19     
     20     mutating func unions() -> [[String]] {
     21         var res = [String: [String]]()
     22         for (email, index) in mapping {
     23             let parent = find(index)
     24             res["(names[parent]!):(parent)", default: []].append(email)
     25         }
     26         return res.map { arg0 in
     27             var (key, val) = arg0
     28             key = String(key.split(separator: ":")[0])
     29             return [key] + val.sorted()
     30         }
     31     }
     32     
     33     init() {
     34         arr = []
     35         size = []
     36         comps = 0
     37     }
     38     
     39     init(n: Int) {
     40         comps = n
     41         arr = Array(repeating: 0, count: n)
     42         size = Array(repeating: 1, count: n)
     43         for i in 0..<n {
     44             arr[i] = i
     45         }
     46     }
     47     
     48     mutating func addEdge(_ edge: [String], _ name: String) {
     49         if mapping[edge[0]] == nil {
     50             arr.append(arr.count)
     51             size.append(1)
     52             mapping[edge[0]] = arr.count - 1
     53             names[arr.count - 1] = name
     54         }
     55         for i in 1..<edge.count {
     56             if mapping[edge[i]] == nil {
     57                 arr.append(arr.count)
     58                 size.append(1)
     59                 mapping[edge[i]] = arr.count - 1
     60             }
     61             union(mapping[edge[0]]!, mapping[edge[i]]!)
     62         }
     63     }
     64     
     65     mutating func find(_ a: String, _ b: String) -> Bool {
     66         guard let indA = mapping[a], let indB = mapping[b] else { return false }
     67         return find(indA, indB)
     68     }
     69     
     70     mutating func find(_ a: Int) -> Int {
     71         return root(a)
     72     }
     73     
     74     mutating func union(_ a: Int, _ b: Int) {
     75         let rootA = root(a)
     76         let rootB = root(b)
     77         if rootA == rootB {
     78             return
     79         }
     80         if size[a] >= size[b] {
     81             arr[rootB] = rootA
     82             size[a] += size[b]
     83         } else {
     84             arr[rootA] = rootB
     85             size[b] += size[a]
     86         }
     87         comps -= 1
     88     }
     89     
     90     mutating func find(_ a: Int, _ b: Int) -> Bool {
     91         return root(a) == root(b)
     92     }
     93     
     94     private mutating func root(_ index: Int) -> Int {
     95         var index = index
     96         while arr[index] != index {
     97             arr[index] = arr[arr[index]]
     98             index = arr[index]
     99         }
    100         return index
    101     }
    102 }

    704ms

     1 class Solution {
     2     class UnionManager {
     3         var idMap = [String: Int]()
     4         var setMap = [Int]()
     5         
     6         func add(element: String) -> Int {
     7             if idMap[element] == nil{
     8                 let idForElement = setMap.count
     9                 idMap[element] = idForElement
    10                 setMap.append(idForElement)
    11             }
    12             return idMap[element] ?? 0
    13         }
    14         
    15         func findSet(id: Int) -> Int {
    16             if setMap[id] != id {
    17                 setMap[id] = findSet(id: setMap[id])
    18             }
    19             return setMap[id]
    20         }
    21         
    22         func union(setOf string1: String, with string2: String) {
    23             let id1 = add(element: string1)
    24             let id2 = add(element: string2)
    25             setMap[findSet(id: id1)] = findSet(id: id2)
    26         }
    27     }
    28     
    29     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
    30         let unionManager = UnionManager()
    31         var emailToName = [String: String]()
    32         let nonEmptyAccounts = accounts.filter{ $0.count > 1 }
    33         for account in nonEmptyAccounts {
    34             let name = account[0]
    35             for email in account[1..<account.count] {
    36                 emailToName[email] = name
    37                 unionManager.union(setOf: email, with: account[1])
    38             }
    39         }
    40         var results: [Int: [String]] = [:]
    41         for (email, id) in unionManager.idMap {
    42             let setId = unionManager.findSet(id: id)
    43             results[setId, default: []].append(email)
    44         }
    45         return results.values.map { $0.sorted() }
    46         .map { emailList in
    47               if let name = emailToName[emailList[0]] {
    48                   return [name] + emailList
    49               } else {
    50                   return emailList
    51               }
    52          }
    53     }
    54 }

    732ms

      1 class Solution {
      2     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
      3         guard accounts.count > 0 else {
      4             return []
      5         }
      6         let graph = Graph<String>(.undirected)
      7         var emailToNameDictionary: [String: String] = [:]
      8         for account in accounts {
      9             let name = account[0]
     10             let source = graph.createVertex(account[1])
     11             for i in 1..<account.count {
     12                 let email = account[i]
     13                 emailToNameDictionary[email] = name
     14                 if i > 1 {
     15                     let destination = graph.createVertex(account[i])
     16                     graph.addUndirectedEdge(between: source, and: destination)
     17                 }
     18             }
     19         }
     20         var mergedAccounts: [[String]] = []
     21         var discovered: Set<Vertex<String>> = []
     22         for vertex in graph.vertice {
     23             if !discovered.contains(vertex) {
     24                 var emails: [String] = []
     25                 depthFirstSearch(graph, vertex, &discovered, &emails)
     26                 let result = [emailToNameDictionary[vertex.val]!] + emails.sorted()
     27                 mergedAccounts.append(result)
     28             }
     29         }
     30         
     31         return mergedAccounts
     32     }
     33 }
     34 
     35 func depthFirstSearch<T: Hashable>(_ graph: Graph<T>, 
     36                                    _ source: Vertex<T>, 
     37                                    _ discovered: inout Set<Vertex<T>>, 
     38                                    _ emails: inout [T]
     39                                   ) {
     40     discovered.insert(source)
     41     emails.append(source.val)
     42     for edge in graph.edges(of: source) {
     43         let destination = edge.destination
     44         if !discovered.contains(destination) {
     45             depthFirstSearch(graph, destination, &discovered, &emails)
     46         }
     47     }
     48 }
     49 
     50 
     51 enum GraphType {
     52     case directed 
     53     case undirected 
     54 }
     55 
     56 struct Vertex<T: Hashable>: Hashable {
     57     public var val: T 
     58     public init(_ val: T) {
     59         self.val = val
     60     }
     61     
     62     public var hashValue : Int {
     63         return val.hashValue
     64     }
     65     
     66     public static func ==(lhs: Vertex<T>, rhs: Vertex<T>) -> Bool {
     67         return lhs.val == rhs.val
     68     }
     69 }
     70 
     71 struct Edge<T: Hashable> {
     72     public let source: Vertex<T>
     73     public let destination: Vertex<T>
     74     public let weight: Double? 
     75     public init(source: Vertex<T>, destination: Vertex<T>, weight: Double? = nil ) {
     76         self.source = source 
     77         self.destination = destination 
     78         self.weight = weight 
     79     }
     80 }
     81 
     82 
     83 class Graph<T: Hashable> {
     84     public var vertice: [Vertex<T>] = []
     85     private var adjacencyList: [Vertex<T>: [Edge<T>]] = [:]
     86     public var type: GraphType 
     87     
     88     public init(_ type: GraphType) {
     89         self.type = type
     90     }
     91     
     92     public func createVertex(_ val: T) -> Vertex<T> {
     93         let source = Vertex(val)
     94         if adjacencyList[source] == nil {
     95             adjacencyList[source] = []
     96             vertice.append(source)
     97         }
     98         return source 
     99     }
    100     
    101     public func addDirectedEdge(from source: Vertex<T>, 
    102                                 to destination: Vertex<T>, 
    103                                 weight: Double? = nil 
    104                                ) {
    105         let edge = Edge(source: source, destination: destination, weight: weight)
    106         adjacencyList[source]?.append(edge)
    107     }
    108     
    109     public func addUndirectedEdge(between source: Vertex<T>,
    110                                   and destination: Vertex<T>, 
    111                                   weight: Double? = nil 
    112                                  ) {
    113         addDirectedEdge(from: source, to: destination, weight: weight)
    114         addDirectedEdge(from: destination, to: source, weight: weight)
    115     }
    116     
    117     public func edges(of source: Vertex<T>) -> [Edge<T>] {
    118         return adjacencyList[source] ?? []
    119     }
    120     
    121     public func weight(from source: Vertex<T>, 
    122                        to destination: Vertex<T>
    123                       ) -> Double? {
    124         return adjacencyList[source]?.first{ $0.destination == destination }?.weight 
    125     }
    126 }

    852ms

     1 class Solution {
     2 // father[儿子] = 老大哥
     3 var father = [Int: Int]()
     4 
     5 func accountsMerge(_ accounts: [[String]]) -> [[String]] {
     6     
     7     // 1 union
     8     let emailToID = getEmailToID(accounts)
     9     for email in emailToID.keys {
    10         let ids = emailToID[email]!
    11         for i in ids {
    12             union(i, ids[0])
    13         }
    14     }
    15     
    16     //2 merge
    17     let idToEmailSet = getIdToEmailSet(accounts)
    18     var mergedAccounts = [[String]]()
    19     
    20     for id in idToEmailSet.keys {
    21         var sortedEmails = idToEmailSet[id]!.sorted()
    22         sortedEmails.insert(accounts[id][0], at: 0)
    23         mergedAccounts.append(sortedEmails)
    24     }
    25     
    26     return mergedAccounts
    27 }
    28 
    29 //find -> 找老大哥
    30 func find(_ id: Int) -> Int {
    31     var id = id
    32     
    33     var path = [Int]()
    34     while let nextID = father[id] {
    35         path.append(id)
    36         id = nextID
    37         
    38     }
    39     
    40     for i in path {
    41         father[i] = id
    42     }
    43     
    44     return id
    45 }
    46 
    47 // union
    48 func union(_ a: Int, _ b: Int) {
    49     let rootA = find(a)
    50     let rootB = find(b)
    51     if rootA != rootB {
    52         father[rootA] = rootB
    53     }
    54 }
    55 
    56 
    57 // 这个只是data处理
    58 func getEmailToID(_ accounts: [[String]]) -> [String: [Int]] {
    59     var emailToID = [String: [Int]]()
    60     
    61     for (userID, acnt) in accounts.enumerated() {
    62         for i in 1..<acnt.count {
    63             let curEmail = acnt[i]
    64             var ids = emailToID[curEmail, default: [Int]()]
    65             ids.append(userID)
    66             emailToID[curEmail] = ids
    67         }
    68     }
    69     
    70     return emailToID
    71 }
    72 
    73 func getIdToEmailSet(_ accounts: [[String]]) -> [Int: Set<String>] {
    74     var idToEmailSet = [Int: Set<String>]()
    75     for id in 0..<accounts.count {
    76         let root_id = find(id)
    77         var emailSet = idToEmailSet[root_id, default: Set<String>()]
    78         
    79         let account = accounts[id]
    80         for i in 1..<account.count {
    81             emailSet.insert(account[i])
    82         }
    83         idToEmailSet[root_id] = emailSet
    84     }
    85     
    86     return idToEmailSet
    87   }
    88 }

    864ms

     1 class Solution {
     2     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
     3         guard accounts.count > 0 else {
     4             return []
     5         }
     6         
     7         var emailToName: [String: String] = [:]
     8         var unionFind = UnionFind<String>()
     9         for account in accounts {
    10             let name = account[0]
    11             let firstEmail = account[1]
    12             unionFind.addSet(firstEmail)
    13             for i in 1..<account.count {
    14                 let email = account[i]
    15                 emailToName[email] = name
    16                 
    17                 if i > 1 {
    18                     let email = account[i]
    19                     unionFind.addSet(email)
    20                     unionFind.union(firstEmail, email)
    21                 }
    22             }
    23         }
    24         
    25         var mergedAccount: [[String]] = []
    26         var storage: [Int: [String]] = [:]
    27         for element in unionFind.index.keys {
    28             let parentIndex = unionFind.find(element)!
    29             if storage[parentIndex] == nil {
    30                 storage[parentIndex] = [element]
    31             } else {
    32                 storage[parentIndex]!.append(element)
    33             }
    34         }
    35         
    36         for emails in storage.values {
    37             let name = emailToName[emails.first!]!
    38             let result = [name] + emails.sorted()
    39             mergedAccount.append(result)
    40         }
    41         
    42         
    43         return mergedAccount
    44     }
    45 }
    46 
    47 
    48 struct UnionFind<T: Hashable> {
    49     public var index: [T: Int] = [:]
    50     private var parent: [Int] = []
    51     private var size: [Int] = []
    52     
    53     public mutating func addSet(_ element: T) {
    54         if index[element] == nil {
    55             index[element] = parent.count 
    56             parent.append(parent.count)
    57             size.append(1)
    58         }
    59     }
    60     
    61     public mutating func find(_ element: T) -> Int? {
    62         guard let index = index[element] else {
    63             return nil 
    64         }
    65         
    66         return setByIndex(index)
    67     }
    68     
    69     private mutating func setByIndex(_ index: Int) -> Int {
    70         if parent[index] == index {
    71             return index 
    72         } else {
    73             parent[index] = setByIndex(parent[index])
    74             return parent[index]
    75         }
    76     }
    77     
    78     public mutating func union(_ element1: T, _ element2: T) {
    79         guard let set1 = find(element1), let set2 = find(element2) else {
    80             return 
    81         }
    82         
    83         if set1 != set2 {
    84             if set1 > set2 {
    85                 parent[set2] = set1
    86                 size[set1] += size[set2]
    87             } else {
    88                 parent[set1] = set2
    89                 size[set2] += size[set1]
    90             }
    91         }
    92     }
    93 }

    Runtime: 1180 ms
    Memory Usage: 21 MB
     1 class Solution {
     2     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
     3         var res:[[String]] = [[String]]()
     4         var root:[String:String] = [String:String]()
     5         var owner:[String:String] = [String:String]()
     6         var m:[String:Set<String>] = [String:Set<String>]()
     7         for account in accounts
     8         {
     9             for i in 1..<account.count
    10             {
    11                 root[account[i]] = account[i]
    12                 owner[account[i]] = account[0]
    13             }
    14         }
    15         for account in accounts
    16         {
    17             var p:String = find(account[1], &root)
    18             for i in 2..<account.count
    19             {
    20                 root[find(account[i], &root)] = p                
    21             }
    22         }
    23         for account in accounts
    24         {
    25             for i in 1..<account.count
    26             {
    27                 let str:String = find(account[i], &root)
    28                 m[str,default:Set<String>()].insert(account[i])
    29             }
    30         }
    31         for (key,val) in m
    32         {
    33             var v:[String] = val.sorted()
    34             v.insert(owner[key,default:String()],at:0)
    35             res.append(v)
    36         }
    37         return res
    38     }
    39     
    40     func find(_ s:String,_ root:inout [String:String]) -> String
    41     {
    42         return root[s] == s ? s : find(root[s,default:String()], &root)
    43     }
    44 }

    2348ms

     1 class Solution {    
     2     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
     3         var emailIdDict: [String:Int] = [:]
     4         var idNameDict: [Int:String] = [:]
     5         var idEmailsDict: [Int:[String]] = [:]
     6         
     7         var curId = 0
     8         
     9         for account in accounts {
    10             // Get name
    11             let name = account[0]
    12             
    13             // Make sure emails exist
    14             guard account.count > 1 else {
    15                 idNameDict[curId] = name
    16                 curId += 1
    17                 continue
    18             }
    19             
    20             // Get emails
    21             let emails = Array(account[1..<account.count])
    22             
    23             // Get matching ids for emails
    24             var idMatches: [Int] = []
    25             emails.forEach({
    26                 guard let id = emailIdDict[$0] else { return }
    27                 idMatches.append(id)
    28             })
    29             idMatches = Array(Set(idMatches)).sorted()
    30             
    31             // Get all combined emails
    32             var allEmails: [String] = emails
    33             idMatches.forEach({
    34                 allEmails += idEmailsDict[$0] ?? []
    35                 idNameDict.removeValue(forKey: $0)
    36                 idEmailsDict.removeValue(forKey: $0)
    37             })
    38             
    39             // Write data to dicts
    40             allEmails.forEach({ emailIdDict[$0] = curId })
    41             idNameDict[curId] = name
    42             idEmailsDict[curId] = allEmails
    43             
    44             // Incrememt ID
    45             curId += 1
    46         }
    47         
    48         return Array(idNameDict.keys).compactMap({
    49             guard let name = idNameDict[$0] else { return nil }
    50             let emails = Array(Set((idEmailsDict[$0] ?? []))).sorted()
    51             return [name] + emails
    52         })
    53     }
    54 }

    2708ms

     1 class Solution {
     2     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
     3         var mAccountsMap = [String: [Set<String>]]()
     4         for sa in accounts {
     5             let sets = mAccountsMap[sa[0]] ?? [Set<String>]()
     6             let mergeset = Set(Array(sa[1..<sa.count]))
     7             let (mergesets, _) = mergeSets(mergeset, sets)
     8             // print(mergesets)
     9             mAccountsMap[sa[0]] = mergesets
    10         }
    11 
    12         var result = [[String]]()
    13         for (act, mailsSetArr) in mAccountsMap {
    14             for set in mailsSetArr {            
    15                 var line = [String]()
    16                 line.append(act)
    17                 line.append(contentsOf: Array(set.sorted()))
    18                 result.append(line)
    19             }
    20         }
    21         return result
    22     }
    23 
    24     func mergeSets(_ mergeSet: Set<String>, _ sets: [Set<String>]) -> ([Set<String>], Bool) {
    25         var ans = sets
    26         var merged = false
    27         var valildUionSet = Set<String>()
    28         for i in 0..<sets.count {
    29             let set = sets[i]
    30             if !set.intersection(mergeSet).isEmpty {
    31                 var uniSets = set
    32                 uniSets.formUnion(mergeSet)
    33                 merged = true
    34                 ans.remove(at: i)
    35                 valildUionSet = uniSets
    36                 break
    37             }
    38         }
    39         if !merged {
    40             ans.append(mergeSet)
    41         }
    42         return merged ? mergeSets(valildUionSet, ans) : (ans, false)
    43     }
    44 }

    2852ms

     1 class Solution {
     2     func accountsMerge(_ accounts: [[String]]) -> [[String]] {
     3         var name = ""
     4         var emailSets = [Set<String>]()
     5         var results = [[String]]()
     6         var sortedAccounts = accounts.sorted { return $0[0] < $1[0] }
     7         for account in sortedAccounts {
     8             if !name.isEmpty && account[0] != name {
     9                 for setFound in emailSets {
    10                     results.append([name] + Array(setFound).sorted())
    11                 }
    12                 emailSets = []
    13             }
    14             name = account[0]
    15             var currentEmailSet = Set(account[1..<account.count])
    16             var newSets = [Set<String>]()
    17             for (i, existingSet) in emailSets.enumerated() {
    18                 if !currentEmailSet.intersection(existingSet).isEmpty {
    19                     currentEmailSet = currentEmailSet.union(existingSet)
    20                 } else {
    21                     newSets.append(existingSet)
    22                 }
    23             }
    24             newSets.append(currentEmailSet)
    25             emailSets = newSets
    26         }
    27         for setFound in emailSets {
    28             results.append([name] + Array(setFound).sorted())
    29         }
    30         return results
    31     }
    32 }
  • 相关阅读:
    设计模式了解
    三次握手
    网络安全常见术语
    threading.Thread 子线程强制停止
    黑帽SEO入门
    Chrome(谷歌)浏览器永久关闭恢复页面提示框(记录)
    FTP文件夹错误:【打开FTP服务器上的文件夹时发生错误。请检查是否有权限访问该文件夹】
    jenkins启动失败,查看状态提示active(exited)
    jenkins打包vue项目报错-未解决
    jenkins迁移报错处理
  • 原文地址:https://www.cnblogs.com/strengthen/p/10513271.html
Copyright © 2011-2022 走看看