/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
/**
* Merge usernames that belong to the same person based on shared emails using optimized DFS.
*
* @param accounts A map where keys are usernames and values are lists of emails
* @return A list of lists, where each inner list contains usernames that belong to the same person
*/
public static List
<List
<String
>> mergeUsernames
(Map
<String, List
<String
>> accounts
) { // Step 1: Create email to username mappings
Map
<String, Set
<String
>> emailToUsernames
= new HashMap
<>();
// For each username, add it to the sets of all its emails
for (Map.
Entry<String, List
<String
>> entry
: accounts.
entrySet()) { String username
= entry.
getKey(); List<String> emails = entry.getValue();
if (!emailToUsernames.containsKey(email)) {
emailToUsernames.put(email, new HashSet<>());
}
emailToUsernames.get(email).add(username);
}
}
// Step 2: Build the graph where usernames are nodes
Map
<String, Set
<String
>> graph
= new HashMap
<>();
// Initialize graph with empty adjacency lists
for (String username
: accounts.
keySet()) { graph.put(username, new HashSet<>());
}
// For each email, connect all usernames that share it
for (Set<String> usernamesWithEmail : emailToUsernames.values()) {
if (usernamesWithEmail.size() > 1) {
// Convert set to list for easier iteration
List<String> usernamesList = new ArrayList<>(usernamesWithEmail);
// Connect each username with the first one (instead of all-to-all)
// This reduces edge creation from O(k²) to O(k) per email
String firstUsername
= usernamesList.
get(0); for (int i = 1; i < usernamesList.size(); i++) {
String otherUsername
= usernamesList.
get(i
); graph.get(firstUsername).add(otherUsername);
graph.get(otherUsername).add(firstUsername);
}
}
}
// Step 3: Perform DFS to find connected components
Set<String> visited = new HashSet<>();
List<List<String>> result = new ArrayList<>();
for (String username
: accounts.
keySet()) { if (!visited.contains(username)) {
List<String> connectedUsernames = new ArrayList<>();
dfs(graph, username, visited, connectedUsernames);
result.add(connectedUsernames);
}
}
return result;
}
/**
* Perform DFS to find all connected usernames.
*/
private static void dfs
(Map
<String, Set
<String
>> graph,
String username,
Set<String> visited, List<String> component) {
visited.add(username);
component.add(username);
for (String neighbor
: graph.
get(username
)) { if (!visited.contains(neighbor)) {
dfs(graph, neighbor, visited, component);
}
}
}
// Example usage
public static void main
(String[] args
) { Map
<String, List
<String
>> accounts
= new HashMap
<>(); accounts.
put("john",
Arrays.
asList("john@gmail.com",
"john@yahoo.com")); accounts.
put("jane",
Arrays.
asList("jane@gmail.com")); accounts.
put("john2",
Arrays.
asList("john@gmail.com")); accounts.
put("mary",
Arrays.
asList("mary@hotmail.com")); accounts.
put("jane2",
Arrays.
asList("jane@gmail.com",
"jane@yahoo.com")); accounts.
put("tom",
Arrays.
asList("tom@gmail.com")); accounts.
put("susan",
Arrays.
asList("susan@outlook.com")); accounts.
put("tom2",
Arrays.
asList("tom@gmail.com",
"thomas@work.com"));
List<List<String>> result = mergeUsernames(accounts);
}
}
LyogcGFja2FnZSB3aGF0ZXZlcjsgLy8gZG9uJ3QgcGxhY2UgcGFja2FnZSBuYW1lISAqLwoKaW1wb3J0IGphdmEudXRpbC4qOwppbXBvcnQgamF2YS5sYW5nLio7CmltcG9ydCBqYXZhLmlvLio7CgovKiBOYW1lIG9mIHRoZSBjbGFzcyBoYXMgdG8gYmUgIk1haW4iIG9ubHkgaWYgdGhlIGNsYXNzIGlzIHB1YmxpYy4gKi8KY2xhc3MgSWRlb25lCnsKICAgIAogICAgLyoqCiAgICAgKiBNZXJnZSB1c2VybmFtZXMgdGhhdCBiZWxvbmcgdG8gdGhlIHNhbWUgcGVyc29uIGJhc2VkIG9uIHNoYXJlZCBlbWFpbHMgdXNpbmcgb3B0aW1pemVkIERGUy4KICAgICAqIAogICAgICogQHBhcmFtIGFjY291bnRzIEEgbWFwIHdoZXJlIGtleXMgYXJlIHVzZXJuYW1lcyBhbmQgdmFsdWVzIGFyZSBsaXN0cyBvZiBlbWFpbHMKICAgICAqIEByZXR1cm4gQSBsaXN0IG9mIGxpc3RzLCB3aGVyZSBlYWNoIGlubmVyIGxpc3QgY29udGFpbnMgdXNlcm5hbWVzIHRoYXQgYmVsb25nIHRvIHRoZSBzYW1lIHBlcnNvbgogICAgICovCiAgICBwdWJsaWMgc3RhdGljIExpc3Q8TGlzdDxTdHJpbmc+PiBtZXJnZVVzZXJuYW1lcyhNYXA8U3RyaW5nLCBMaXN0PFN0cmluZz4+IGFjY291bnRzKSB7CiAgICAgICAgLy8gU3RlcCAxOiBDcmVhdGUgZW1haWwgdG8gdXNlcm5hbWUgbWFwcGluZ3MKICAgICAgICBNYXA8U3RyaW5nLCBTZXQ8U3RyaW5nPj4gZW1haWxUb1VzZXJuYW1lcyA9IG5ldyBIYXNoTWFwPD4oKTsKICAgICAgICAKICAgICAgICAvLyBGb3IgZWFjaCB1c2VybmFtZSwgYWRkIGl0IHRvIHRoZSBzZXRzIG9mIGFsbCBpdHMgZW1haWxzCiAgICAgICAgZm9yIChNYXAuRW50cnk8U3RyaW5nLCBMaXN0PFN0cmluZz4+IGVudHJ5IDogYWNjb3VudHMuZW50cnlTZXQoKSkgewogICAgICAgICAgICBTdHJpbmcgdXNlcm5hbWUgPSBlbnRyeS5nZXRLZXkoKTsKICAgICAgICAgICAgTGlzdDxTdHJpbmc+IGVtYWlscyA9IGVudHJ5LmdldFZhbHVlKCk7CiAgICAgICAgICAgIAogICAgICAgICAgICBmb3IgKFN0cmluZyBlbWFpbCA6IGVtYWlscykgewogICAgICAgICAgICAgICAgaWYgKCFlbWFpbFRvVXNlcm5hbWVzLmNvbnRhaW5zS2V5KGVtYWlsKSkgewogICAgICAgICAgICAgICAgICAgIGVtYWlsVG9Vc2VybmFtZXMucHV0KGVtYWlsLCBuZXcgSGFzaFNldDw+KCkpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgZW1haWxUb1VzZXJuYW1lcy5nZXQoZW1haWwpLmFkZCh1c2VybmFtZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gU3RlcCAyOiBCdWlsZCB0aGUgZ3JhcGggd2hlcmUgdXNlcm5hbWVzIGFyZSBub2RlcwogICAgICAgIE1hcDxTdHJpbmcsIFNldDxTdHJpbmc+PiBncmFwaCA9IG5ldyBIYXNoTWFwPD4oKTsKICAgICAgICAKICAgICAgICAvLyBJbml0aWFsaXplIGdyYXBoIHdpdGggZW1wdHkgYWRqYWNlbmN5IGxpc3RzCiAgICAgICAgZm9yIChTdHJpbmcgdXNlcm5hbWUgOiBhY2NvdW50cy5rZXlTZXQoKSkgewogICAgICAgICAgICBncmFwaC5wdXQodXNlcm5hbWUsIG5ldyBIYXNoU2V0PD4oKSk7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIC8vIEZvciBlYWNoIGVtYWlsLCBjb25uZWN0IGFsbCB1c2VybmFtZXMgdGhhdCBzaGFyZSBpdAogICAgICAgIGZvciAoU2V0PFN0cmluZz4gdXNlcm5hbWVzV2l0aEVtYWlsIDogZW1haWxUb1VzZXJuYW1lcy52YWx1ZXMoKSkgewogICAgICAgICAgICBpZiAodXNlcm5hbWVzV2l0aEVtYWlsLnNpemUoKSA+IDEpIHsKICAgICAgICAgICAgICAgIC8vIENvbnZlcnQgc2V0IHRvIGxpc3QgZm9yIGVhc2llciBpdGVyYXRpb24KICAgICAgICAgICAgICAgIExpc3Q8U3RyaW5nPiB1c2VybmFtZXNMaXN0ID0gbmV3IEFycmF5TGlzdDw+KHVzZXJuYW1lc1dpdGhFbWFpbCk7CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIC8vIENvbm5lY3QgZWFjaCB1c2VybmFtZSB3aXRoIHRoZSBmaXJzdCBvbmUgKGluc3RlYWQgb2YgYWxsLXRvLWFsbCkKICAgICAgICAgICAgICAgIC8vIFRoaXMgcmVkdWNlcyBlZGdlIGNyZWF0aW9uIGZyb20gTyhrwrIpIHRvIE8oaykgcGVyIGVtYWlsCiAgICAgICAgICAgICAgICBTdHJpbmcgZmlyc3RVc2VybmFtZSA9IHVzZXJuYW1lc0xpc3QuZ2V0KDApOwogICAgICAgICAgICAgICAgZm9yIChpbnQgaSA9IDE7IGkgPCB1c2VybmFtZXNMaXN0LnNpemUoKTsgaSsrKSB7CiAgICAgICAgICAgICAgICAgICAgU3RyaW5nIG90aGVyVXNlcm5hbWUgPSB1c2VybmFtZXNMaXN0LmdldChpKTsKICAgICAgICAgICAgICAgICAgICBncmFwaC5nZXQoZmlyc3RVc2VybmFtZSkuYWRkKG90aGVyVXNlcm5hbWUpOwogICAgICAgICAgICAgICAgICAgIGdyYXBoLmdldChvdGhlclVzZXJuYW1lKS5hZGQoZmlyc3RVc2VybmFtZSk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgCiAgICAgICAgLy8gU3RlcCAzOiBQZXJmb3JtIERGUyB0byBmaW5kIGNvbm5lY3RlZCBjb21wb25lbnRzCiAgICAgICAgU2V0PFN0cmluZz4gdmlzaXRlZCA9IG5ldyBIYXNoU2V0PD4oKTsKICAgICAgICBMaXN0PExpc3Q8U3RyaW5nPj4gcmVzdWx0ID0gbmV3IEFycmF5TGlzdDw+KCk7CiAgICAgICAgCiAgICAgICAgZm9yIChTdHJpbmcgdXNlcm5hbWUgOiBhY2NvdW50cy5rZXlTZXQoKSkgewogICAgICAgICAgICBpZiAoIXZpc2l0ZWQuY29udGFpbnModXNlcm5hbWUpKSB7CiAgICAgICAgICAgICAgICBMaXN0PFN0cmluZz4gY29ubmVjdGVkVXNlcm5hbWVzID0gbmV3IEFycmF5TGlzdDw+KCk7CiAgICAgICAgICAgICAgICBkZnMoZ3JhcGgsIHVzZXJuYW1lLCB2aXNpdGVkLCBjb25uZWN0ZWRVc2VybmFtZXMpOwogICAgICAgICAgICAgICAgcmVzdWx0LmFkZChjb25uZWN0ZWRVc2VybmFtZXMpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIAogICAgICAgIHJldHVybiByZXN1bHQ7CiAgICB9CiAgICAKICAgIC8qKgogICAgICogUGVyZm9ybSBERlMgdG8gZmluZCBhbGwgY29ubmVjdGVkIHVzZXJuYW1lcy4KICAgICAqLwogICAgcHJpdmF0ZSBzdGF0aWMgdm9pZCBkZnMoTWFwPFN0cmluZywgU2V0PFN0cmluZz4+IGdyYXBoLCBTdHJpbmcgdXNlcm5hbWUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBTZXQ8U3RyaW5nPiB2aXNpdGVkLCBMaXN0PFN0cmluZz4gY29tcG9uZW50KSB7CiAgICAgICAgdmlzaXRlZC5hZGQodXNlcm5hbWUpOwogICAgICAgIGNvbXBvbmVudC5hZGQodXNlcm5hbWUpOwogICAgICAgIAogICAgICAgIGZvciAoU3RyaW5nIG5laWdoYm9yIDogZ3JhcGguZ2V0KHVzZXJuYW1lKSkgewogICAgICAgICAgICBpZiAoIXZpc2l0ZWQuY29udGFpbnMobmVpZ2hib3IpKSB7CiAgICAgICAgICAgICAgICBkZnMoZ3JhcGgsIG5laWdoYm9yLCB2aXNpdGVkLCBjb21wb25lbnQpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgCiAgICAvLyBFeGFtcGxlIHVzYWdlCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgTWFwPFN0cmluZywgTGlzdDxTdHJpbmc+PiBhY2NvdW50cyA9IG5ldyBIYXNoTWFwPD4oKTsKICAgICAgICBhY2NvdW50cy5wdXQoImpvaG4iLCBBcnJheXMuYXNMaXN0KCJqb2huQGdtYWlsLmNvbSIsICJqb2huQHlhaG9vLmNvbSIpKTsKICAgICAgICBhY2NvdW50cy5wdXQoImphbmUiLCBBcnJheXMuYXNMaXN0KCJqYW5lQGdtYWlsLmNvbSIpKTsKICAgICAgICBhY2NvdW50cy5wdXQoImpvaG4yIiwgQXJyYXlzLmFzTGlzdCgiam9obkBnbWFpbC5jb20iKSk7CiAgICAgICAgYWNjb3VudHMucHV0KCJtYXJ5IiwgQXJyYXlzLmFzTGlzdCgibWFyeUBob3RtYWlsLmNvbSIpKTsKICAgICAgICBhY2NvdW50cy5wdXQoImphbmUyIiwgQXJyYXlzLmFzTGlzdCgiamFuZUBnbWFpbC5jb20iLCAiamFuZUB5YWhvby5jb20iKSk7CiAgICAgICAgYWNjb3VudHMucHV0KCJ0b20iLCBBcnJheXMuYXNMaXN0KCJ0b21AZ21haWwuY29tIikpOwogICAgICAgIGFjY291bnRzLnB1dCgic3VzYW4iLCBBcnJheXMuYXNMaXN0KCJzdXNhbkBvdXRsb29rLmNvbSIpKTsKICAgICAgICBhY2NvdW50cy5wdXQoInRvbTIiLCBBcnJheXMuYXNMaXN0KCJ0b21AZ21haWwuY29tIiwgInRob21hc0B3b3JrLmNvbSIpKTsKICAgICAgICAKICAgICAgICBMaXN0PExpc3Q8U3RyaW5nPj4gcmVzdWx0ID0gbWVyZ2VVc2VybmFtZXMoYWNjb3VudHMpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbihyZXN1bHQpOwogICAgfQoKfQ==