721. Accounts Merge

O texto da tarefa é traduzido do russo para o idioma selecionado. O código permanece sem alterações.

Дан список аккаунтов, в котором каждый element accounts[i] - это список строк, где первый element accounts[i][0] - это имя, а остальные elementы - это email, представляющие электронную почту аккаунта. Теперь мы хотим объединить эти аккаунты. Два аккаунта определенно принадлежат одному человеку, если у обоих аккаунтов есть какой-то общий email. Обратите внимание, что даже если два аккаунта имеют одинаковое имя, они могут принадлежать разным людям, поскольку у людей могут быть одинаковые имена. Изначально у человека может быть любое количество счетов, но все его счета обязательно должны иметь одинаковое имя. После объединения счетов return счета в следующем формате: первый element каждого счета - имя, а остальные elementы - электронные письма в отсортированном порядке. Сами аккаунты могут быть возвращены в любом порядке.

Exemplo:

nput: accounts = [["John","johnsmith@mail.com","john_newyork@mail.com"],["John","johnsmith@mail.com","john00@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]]

Output: [["John","john00@mail.com","john_newyork@mail.com","johnsmith@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]]

C# solução

correspondente/original
using System;
using System.Collections.Generic;
public class Solution {
    public IList<IList<string>> AccountsMerge(IList<IList<string>> accounts) {
        var emailToName = new Dictionary<string, string>();
        var graph = new Dictionary<string, HashSet<string>>();
        
        foreach (var account in accounts) {
            string name = account[0];
            string firstEmail = account[1];
            foreach (var email in account.Skip(1)) {
                if (!graph.ContainsKey(firstEmail)) graph[firstEmail] = new HashSet<string>();
                if (!graph.ContainsKey(email)) graph[email] = new HashSet<string>();
                graph[firstEmail].Add(email);
                graph[email].Add(firstEmail);
                emailToName[email] = name;
            }
        }
        
        var seen = new HashSet<string>();
        var mergedAccounts = new List<IList<string>>();
        
        foreach (var email in emailToName.Keys) {
            if (!seen.Contains(email)) {
                var emails = new List<string>();
                var stack = new Stack<string>();
                stack.Push(email);
                while (stack.Count > 0) {
                    var node = stack.Pop();
                    if (!seen.Contains(node)) {
                        seen.Add(node);
                        emails.Add(node);
                        foreach (var neighbor in graph[node]) {
                            stack.Push(neighbor);
                        }
                    }
                }
                emails.Sort();
                mergedAccounts.Add(new List<string> { emailToName[email] });
                mergedAccounts[mergedAccounts.Count - 1].AddRange(emails);
            }
        }
        
        return mergedAccounts;
    }
}

C++ solução

rascunho automático, revisar antes de enviar
#include <bits/stdc++.h>
using namespace std;

// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
    public IList<vector<string>> AccountsMerge(IList<vector<string>> accounts) {
        var emailToName = new unordered_map<string, string>();
        var graph = new unordered_map<string, HashSet<string>>();
        
        foreach (var account in accounts) {
            string name = account[0];
            string firstEmail = account[1];
            foreach (var email in account.Skip(1)) {
                if (!graph.count(firstEmail)) graph[firstEmail] = new HashSet<string>();
                if (!graph.count(email)) graph[email] = new HashSet<string>();
                graph[firstEmail].push_back(email);
                graph[email].push_back(firstEmail);
                emailToName[email] = name;
            }
        }
        
        var seen = new HashSet<string>();
        var mergedAccounts = new List<vector<string>>();
        
        foreach (var email in emailToName.Keys) {
            if (!seen.Contains(email)) {
                var emails = new List<string>();
                var stack = new stack<string>();
                stack.push(email);
                while (stack.size() > 0) {
                    var node = stack.pop();
                    if (!seen.Contains(node)) {
                        seen.push_back(node);
                        emails.push_back(node);
                        foreach (var neighbor in graph[node]) {
                            stack.push(neighbor);
                        }
                    }
                }
                emails.Sort();
                mergedAccounts.push_back(new List<string> { emailToName[email] });
                mergedAccounts[mergedAccounts.size() - 1].AddRange(emails);
            }
        }
        
        return mergedAccounts;
    }
}

Java solução

correspondente/original
import java.util.*;

public class Solution {
    public List<List<String>> accountsMerge(List<List<String>> accounts) {
        Map<String, String> emailToName = new HashMap<>();
        Map<String, Set<String>> graph = new HashMap<>();
        
        for (List<String> account : accounts) {
            String name = account.get(0);
            String firstEmail = account.get(1);
            for (String email : account.subList(1, account.size())) {
                graph.computeIfAbsent(firstEmail, x -> new HashSet<>()).add(email);
                graph.computeIfAbsent(email, x -> new HashSet<>()).add(firstEmail);
                emailToName.put(email, name);
            }
        }
        
        Set<String> seen = new HashSet<>();
        List<List<String>> mergedAccounts = new ArrayList<>();
        
        for (String email : emailToName.keySet()) {
            if (!seen.contains(email)) {
                List<String> emails = new ArrayList<>();
                Stack<String> stack = new Stack<>();
                stack.push(email);
                while (!stack.isEmpty()) {
                    String node = stack.pop();
                    if (!seen.contains(node)) {
                        seen.add(node);
                        emails.add(node);
                        for (String neighbor : graph.get(node)) {
                            stack.push(neighbor);
                        }
                    }
                }
                Collections.sort(emails);
                mergedAccounts.add(new ArrayList<>(Arrays.asList(emailToName.get(email))));
                mergedAccounts.get(mergedAccounts.size() - 1).addAll(emails);
            }
        }
        
        return mergedAccounts;
    }
}

JavaScript solução

correspondente/original
var accountsMerge = function(accounts) {
    const emailToName = {};
    const graph = {};
    
    for (let account of accounts) {
        const name = account[0];
        const firstEmail = account[1];
        for (let email of account.slice(1)) {
            if (!graph[firstEmail]) graph[firstEmail] = new Set();
            if (!graph[email]) graph[email] = new Set();
            graph[firstEmail].add(email);
            graph[email].add(firstEmail);
            emailToName[email] = name;
        }
    }
    
    const seen = new Set();
    const dfs = (email) => {
        const stack = [email];
        const result = [];
        while (stack.length) {
            const node = stack.pop();
            if (!seen.has(node)) {
                seen.add(node);
                result.push(node);
                for (let neighbor of graph[node]) {
                    stack.push(neighbor);
                }
            }
        }
        return result;
    };
    
    const mergedAccounts = [];
    for (let email in emailToName) {
        if (!seen.has(email)) {
            const emails = dfs(email);
            mergedAccounts.push([emailToName[email], ...emails.sort()]);
        }
    }
    
    return mergedAccounts;
};

Python solução

correspondente/original
def accountsMerge(accounts):
    from collections import defaultdict

    graph = defaultdict(set)
    email_to_name = {}

    for account in accounts:
        name = account[0]
        first_email = account[1]
        for email in account[1:]:
            graph[first_email].add(email)
            graph[email].add(first_email)
            email_to_name[email] = name

    visited = set()
    merged_accounts = []

    def dfs(email):
        emails = [email]
        stack = [email]
        while stack:
            node = stack.pop()
            for neighbor in graph[node]:
                if neighbor not in visited:
                    visited.add(neighbor)
                    stack.append(neighbor)
                    emails.append(neighbor)
        return emails

    for email in graph:
        if email not in visited:
            visited.add(email)
            emails = dfs(email)
            merged_accounts.append([email_to_name[email]] + sorted(emails))

    return merged_accounts

Go solução

correspondente/original
package main

import (
    "sort"
)

func accountsMerge(accounts [][]string) [][]string {
    emailToName := make(map[string]string)
    graph := make(map[string]map[string]struct{})
    
    for _, account := range accounts {
        name := account[0]
        firstEmail := account[1]
        for _, email := range account[1:] {
            if graph[firstEmail] == nil {
                graph[firstEmail] = make(map[string]struct{})
            }
            if graph[email] == nil {
                graph[email] = make(map[string]struct{})
            }
            graph[firstEmail][email] = struct{}{}
            graph[email][firstEmail] = struct{}{}
            emailToName[email] = name
        }
    }
    
    seen := make(map[string]struct{})
    var mergedAccounts [][]string
    
    for email := range emailToName {
        if _, ok := seen[email]; !ok {
            var emails []string
            stack := []string{email}
            for len(stack) > 0 {
                node := stack[len(stack)-1]
                stack = stack[:len(stack)-1]
                if _, ok := seen[node]; !ok {
                    seen[node] = struct{}{}
                    emails = append(emails, node)
                    for neighbor := range graph[node] {
                        stack = append(stack, neighbor)
                    }
                }
            }
            sort.Strings(emails)
            account := append([]string{emailToName[email]}, emails...)
            mergedAccounts = append(mergedAccounts, account)
        }
    }
    
    return mergedAccounts
}

Algorithm

Создайте grafo, в котором узлы представляют email-адреса, а ребра соединяют email-адреса, принадлежащие одному аккаунту.

Пройдите по grafoу, чтобы find все связанные компоненты, которые представляют объединенные аккаунты.

Для каждой связанной компоненты, соберите email-адреса, отсортируйте их и добавьте имя пользователя в начало списка.

😎

Vacancies for this task

vagas ativas with overlapping task tags are mostradas.

Todas as vagas
Ainda não há vagas ativas.