Open In App

Find same contacts in a list of contacts

Last Updated : 10 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a list of contacts containing the username, email and phone number in any order. Identify the same contacts (i.e., the same person having many contacts) and output the same contacts together. 

Notes: 

  1. A contact can store its three fields in any order, i.e., a phone number can appear before username or username can appear before the phone number.
  2. Two contacts are the same if they have either the same username or email or phone number. 

Example: 

Input: contact[] = 
     { {"Gaurav", "gaurav@gmail.com", "gaurav@gfgQA.com"},
       { "Lucky", "lucky@gmail.com", "+1234567"},
       { "gaurav123", "+5412312", "gaurav123@skype.com"}.
       { "gaurav1993", "+5412312", "gaurav@gfgQA.com"}
     }
Output:
   0 2 3
   1 
contact[2] is same as contact[3] because they both have same
contact number.
contact[0] is same as contact[3] because they both have same
e-mail address.
Therefore, contact[0] and contact[2] are also same.

We strongly recommend you to minimize your browser and try this yourself first. 
Input is basically an array of structures. A structure contains three fields such that any field can represent any detail about a contact.

The idea is to first create a graph of contacts using given array. In the graph, there is an edge between vertex i to vertex j if they both have either same username or same email or same phone number. Once the graph is constructed, the task reduces to finding connected components in an undirected graph. We can find connected components either by doing DFS or BFS starting from every unvisited vertex. In below code, DFS is used.

Below is implementation of this idea.  

C++




// A C++ program to find same contacts in a list of contacts
#include<bits/stdc++.h>
using namespace std;
 
// Structure for storing contact details.
struct contact
{
    string field1, field2, field3;
};
 
// A utility function to fill entries in adjacency matrix
// representation of graph
void buildGraph(contact arr[], int n, int *mat[])
{
    // Initialize the adjacency matrix
    for (int i=0; i<n; i++)
       for (int j=0; j<n; j++)
           mat[i][j] = 0;
 
    // Traverse through all contacts
    for (int i = 0; i < n; i++) {
 
        // Add mat from i to j and vice versa, if possible.
        // Since length of each contact field is at max some
        // constant. (say 30) so body execution of this for
        // loop takes constant time.
        for (int j = i+1; j < n; j++)
            if (arr[i].field1 == arr[j].field1 ||
                arr[i].field1 == arr[j].field2 ||
                arr[i].field1 == arr[j].field3 ||
                arr[i].field2 == arr[j].field1 ||
                arr[i].field2 == arr[j].field2 ||
                arr[i].field2 == arr[j].field3 ||
                arr[i].field3 == arr[j].field1 ||
                arr[i].field3 == arr[j].field2 ||
                arr[i].field3 == arr[j].field3)
            {
                mat[i][j] = 1;
                mat[j][i] = 1;
                break;
            }
    }
}
 
// A recursive function to perform DFS with vertex i as source
void DFSvisit(int i, int *mat[], bool visited[], vector<int>& sol, int n)
{
    visited[i] = true;
    sol.push_back(i);
 
    for (int j = 0; j < n; j++)
        if (mat[i][j] && !visited[j])
            DFSvisit(j, mat, visited, sol, n);
}
 
// Finds similar contacts in an array of contacts
void findSameContacts(contact arr[], int n)
{
    // vector for storing the solution
    vector<int> sol;
 
    // Declare 2D adjacency matrix for mats
    int **mat = new int*[n];
 
    for (int i = 0; i < n; i++)
        mat[i] = new int[n];
 
    // visited array to keep track of visited nodes
    bool visited[n];
    memset(visited, 0, sizeof(visited));
 
    // Fill adjacency matrix
    buildGraph(arr, n, mat);
 
    // Since, we made a graph with contacts as nodes with fields as links.
    // two nodes are linked if they represent the same person.
    // so, total number of connected components and nodes in each component
    // will be our answer.
    for (int i = 0; i < n; i++)
    {
        if (!visited[i])
        {
            DFSvisit(i, mat, visited, sol, n);
 
            // Add delimiter to separate nodes of one component from other.
            sol.push_back(-1);
        }
    }
 
    // Print the solution
    for (int i = 0; i < sol.size(); i++)
        if (sol[i] == -1) cout << endl;
        else cout << sol[i] << " ";
}
 
// Drive Code
int main()
{
    contact arr[] = {{"Gaurav", "gaurav@gmail.com", "gaurav@gfgQA.com"},
                     {"Lucky", "lucky@gmail.com", "+1234567"},
                     {"gaurav123", "+5412312", "gaurav123@skype.com"},
                     {"gaurav1993", "+5412312", "gaurav@gfgQA.com"},
                     {"raja", "+2231210", "raja@gfg.com"},
                     {"bahubali", "+878312", "raja"}
                    };
 
    int n = sizeof arr / sizeof arr[0];
    findSameContacts(arr, n);
    return 0;
}


Java




// A Java program to find same contacts in a list of
// contacts
import java.util.ArrayList;
 
public class GFG {
 
  // Structure for storing contact details.
  static class contact {
    String field1, field2, field3;
    contact(String s1, String s2, String s3)
    {
      field1 = s1;
      field2 = s2;
      field3 = s3;
    }
  };
 
  // A utility function to fill entries in adjacency
  // matrix representation of graph
  static void
    buildGraph(contact arr[], int n,
               ArrayList<ArrayList<Integer> > mat)
  {
    // Initialize the adjacency matrix
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        mat.get(i).add(0);
 
    // Traverse through all contacts
    for (int i = 0; i < n; i++) {
 
      // Add mat from i to j and vice versa, if
      // possible. Since length of each contact field
      // is at max some constant. (say 30) so body
      // execution of this for loop takes constant
      // time.
      for (int j = i + 1; j < n; j++)
        if (arr[i].field1 == arr[j].field1
            || arr[i].field1 == arr[j].field2
            || arr[i].field1 == arr[j].field3
            || arr[i].field2 == arr[j].field1
            || arr[i].field2 == arr[j].field2
            || arr[i].field2 == arr[j].field3
            || arr[i].field3 == arr[j].field1
            || arr[i].field3 == arr[j].field2
            || arr[i].field3 == arr[j].field3) {
          mat.get(i).set(j, 1);
          mat.get(j).set(i, 1);
          break;
        }
    }
  }
 
  // A recursive function to perform DFS with vertex i as
  // source
  static void DFSvisit(int i,
                       ArrayList<ArrayList<Integer> > mat,
                       boolean visited[],
                       ArrayList<Integer> sol, int n)
  {
    visited[i] = true;
    sol.add(i);
 
    for (int j = 0; j < n; j++)
      if (mat.get(i).get(j) != 0 && !visited[j])
        DFSvisit(j, mat, visited, sol, n);
  }
 
  // Finds similar contacts in an array of contacts
  static void findSameContacts(contact arr[], int n)
  {
    // vector for storing the solution
    ArrayList<Integer> sol = new ArrayList<>();
 
    // Declare 2D adjacency matrix for mats
    ArrayList<ArrayList<Integer> > mat
      = new ArrayList<>();
 
    for (int i = 0; i < n; i++)
      mat.add(new ArrayList<>());
 
    // visited array to keep track of visited nodes
    boolean[] visited = new boolean[n];
 
    // Fill adjacency matrix
    buildGraph(arr, n, mat);
 
    // Since, we made a graph with contacts as nodes
    // with fields as links. two nodes are linked if
    // they represent the same person. so, total number
    // of connected components and nodes in each
    // component will be our answer.
    for (int i = 0; i < n; i++) {
      if (!visited[i]) {
        DFSvisit(i, mat, visited, sol, n);
 
        // Add delimiter to separate nodes of one
        // component from other.
        sol.add(-1);
      }
    }
 
    // Print the solution
    for (int i = 0; i < sol.size(); i++)
      if (sol.get(i) == -1)
        System.out.println();
    else
      System.out.print(sol.get(i) + " ");
  }
 
  // Drive Code
  public static void main(String[] args)
  {
    contact arr[] = {
      new contact("Gaurav", "gaurav@gmail.com",
                  "gaurav@gfgQA.com"),
      new contact("Lucky", "lucky@gmail.com",
                  "+1234567"),
      new contact("gaurav123", "+5412312",
                  "gaurav123@skype.com"),
      new contact("gaurav1993", "+5412312",
                  "gaurav@gfgQA.com"),
      new contact("raja", "+2231210", "raja@gfg.com"),
      new contact("bahubali", "+878312", "raja")
      };
 
    int n = arr.length;
    findSameContacts(arr, n);
  }
}
 
// This code is contributed by Karandeep1234


Python3




# A Python3 program to find same contacts
# in a list of contacts
 
# Structure for storing contact details.
class contact:
    def __init__(self, field1,
                       field2, field3):
        self.field1 = field1
        self.field2 = field2
        self.field3 = field3
 
# A utility function to fill entries in
# adjacency matrix representation of graph
def buildGraph(arr, n, mat):
     
    # Initialize the adjacency matrix
    for i in range(n):
        for j in range(n):
            mat[i][j] = 0
 
    # Traverse through all contacts
    for i in range(n):
 
        # Add mat from i to j and vice versa,
        # if possible. Since length of each
        # contact field is at max some constant.
        # (say 30) so body execution of this for
        # loop takes constant time.
        for j in range(i + 1, n):
            if (arr[i].field1 == arr[j].field1 or
                arr[i].field1 == arr[j].field2 or
                arr[i].field1 == arr[j].field3 or
                arr[i].field2 == arr[j].field1 or
                arr[i].field2 == arr[j].field2 or
                arr[i].field2 == arr[j].field3 or
                arr[i].field3 == arr[j].field1 or
                arr[i].field3 == arr[j].field2 or
                arr[i].field3 == arr[j].field3):
                mat[i][j] = 1
                mat[j][i] = 1
                break
 
# A recursive function to perform DFS
# with vertex i as source
def DFSvisit(i, mat, visited, sol, n):
    visited[i] = True
    sol.append(i)
 
    for j in range(n):
        if (mat[i][j] and not visited[j]):
            DFSvisit(j, mat, visited, sol, n)
 
# Finds similar contacts in an
# array of contacts
def findSameContacts(arr, n):
     
    # vector for storing the solution
    sol = []
 
    # Declare 2D adjacency matrix for mats
    mat = [[None] * n for i in range(n)]
 
    # visited array to keep track
    # of visited nodes
    visited = [0] * n
 
    # Fill adjacency matrix
    buildGraph(arr, n, mat)
 
    # Since, we made a graph with contacts 
    # as nodes with fields as links. Two
    # nodes are linked if they represent
    # the same person. So, total number of
    # connected components and nodes in each
    # component will be our answer.
    for i in range(n):
        if (not visited[i]):
            DFSvisit(i, mat, visited, sol, n)
 
            # Add delimiter to separate nodes
            # of one component from other.
            sol.append(-1)
 
    # Print the solution
    for i in range(len(sol)):
        if (sol[i] == -1):
            print()
        else:
            print(sol[i], end = " ")
 
# Driver Code
if __name__ == '__main__':
    arr = [contact("Gaurav", "gaurav@gmail.com", "gaurav@gfgQA.com"),
           contact("Lucky", "lucky@gmail.com", "+1234567"),
           contact("gaurav123", "+5412312", "gaurav123@skype.com"),
           contact("gaurav1993", "+5412312", "gaurav@gfgQA.com"),
           contact("raja", "+2231210", "raja@gfg.com"),
           contact("bahubali", "+878312", "raja")]
 
    n = len(arr)
    findSameContacts(arr, n)
 
# This code is contributed by PranchalK


C#




// A C# program to find same contacts in a list of
// contacts
using System;
using System.Collections;
using System.Collections.Generic;
 
public class GFG {
 
  // Structure for storing contact details.
  public class contact {
    public string field1, field2, field3;
    public contact(string s1, string s2, string s3)
    {
      field1 = s1;
      field2 = s2;
      field3 = s3;
    }
  };
 
  // A utility function to fill entries in adjacency
  // matrix representation of graph
  static void buildGraph(contact[] arr, int n,
                         List<List<int> > mat)
  {
    // Initialize the adjacency matrix
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        mat[i].Add(0);
 
    // Traverse through all contacts
    for (int i = 0; i < n; i++) {
 
      // Add mat from i to j and vice versa, if
      // possible. Since length of each contact field
      // is at max some constant. (say 30) so body
      // execution of this for loop takes constant
      // time.
      for (int j = i + 1; j < n; j++)
        if (arr[i].field1 == arr[j].field1
            || arr[i].field1 == arr[j].field2
            || arr[i].field1 == arr[j].field3
            || arr[i].field2 == arr[j].field1
            || arr[i].field2 == arr[j].field2
            || arr[i].field2 == arr[j].field3
            || arr[i].field3 == arr[j].field1
            || arr[i].field3 == arr[j].field2
            || arr[i].field3 == arr[j].field3) {
          mat[i][j] = 1;
          mat[j][i] = 1;
          break;
        }
    }
  }
 
  // A recursive function to perform DFS with vertex i as
  // source
  static void DFSvisit(int i, List<List<int> > mat,
                       bool[] visited, List<int> sol,
                       int n)
  {
    visited[i] = true;
    sol.Add(i);
 
    for (int j = 0; j < n; j++)
      if (mat[i][j] != 0 && !visited[j])
        DFSvisit(j, mat, visited, sol, n);
  }
 
  // Finds similar contacts in an array of contacts
  static void findSameContacts(contact[] arr, int n)
  {
    // vector for storing the solution
    List<int> sol = new List<int>();
 
    // Declare 2D adjacency matrix for mats
    List<List<int> > mat = new List<List<int> >();
 
    for (int i = 0; i < n; i++)
      mat.Add(new List<int>());
 
    // visited array to keep track of visited nodes
    bool[] visited = new bool[n];
 
    // Fill adjacency matrix
    buildGraph(arr, n, mat);
 
    // Since, we made a graph with contacts as nodes
    // with fields as links. two nodes are linked if
    // they represent the same person. so, total number
    // of connected components and nodes in each
    // component will be our answer.
    for (int i = 0; i < n; i++) {
      if (!visited[i]) {
        DFSvisit(i, mat, visited, sol, n);
 
        // Add delimiter to separate nodes of one
        // component from other.
        sol.Add(-1);
      }
    }
 
    // Print the solution
    for (int i = 0; i < sol.Count; i++)
      if (sol[i] == -1)
        Console.WriteLine();
    else
      Console.Write(sol[i] + " ");
  }
 
  // Drive Code
  public static void Main(string[] args)
  {
    contact[] arr = {
      new contact("Gaurav", "gaurav@gmail.com",
                  "gaurav@gfgQA.com"),
      new contact("Lucky", "lucky@gmail.com",
                  "+1234567"),
      new contact("gaurav123", "+5412312",
                  "gaurav123@skype.com"),
      new contact("gaurav1993", "+5412312",
                  "gaurav@gfgQA.com"),
      new contact("raja", "+2231210", "raja@gfg.com"),
      new contact("bahubali", "+878312", "raja")
      };
 
    int n = arr.Length;
    findSameContacts(arr, n);
  }
}
 
// This code is contributed by Karandeep1234


Javascript




// JS code for the above approach
 
// Structure for storing contact details.
class Contact {
  constructor(field1, field2, field3) {
    this.field1 = field1;
    this.field2 = field2;
    this.field3 = field3;
  }
}
 
// A utility function to fill entries in
// adjacency matrix representation of graph
function buildGraph(arr, n, mat) {
  // Initialize the adjacency matrix
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      mat[i][j] = 0;
    }
  }
 
  // Traverse through all contacts
  for (let i = 0; i < n; i++) {
    // Add mat from i to j and vice versa,
    // if possible. Since length of each
    // contact field is at max some constant.
    // (say 30) so body execution of this for
    // loop takes constant time.
    for (let j = i + 1; j < n; j++) {
      if (arr[i].field1 === arr[j].field1 ||
          arr[i].field1 === arr[j].field2 ||
          arr[i].field1 === arr[j].field3 ||
          arr[i].field2 === arr[j].field1 ||
          arr[i].field2 === arr[j].field2 ||
          arr[i].field2 === arr[j].field3 ||
          arr[i].field3 === arr[j].field1 ||
          arr[i].field3 === arr[j].field2 ||
          arr[i].field3 === arr[j].field3) {
        mat[i][j] = 1;
        mat[j][i] = 1;
        break;
      }
    }
  }
}
 
// A recursive function to perform DFS
// with vertex i as source
function DFSvisit(i, mat, visited, sol, n) {
  visited[i] = true;
  sol.push(i);
 
  for (let j = 0; j < n; j++) {
    if (mat[i][j] && !visited[j]) {
      DFSvisit(j, mat, visited, sol, n);
    }
  }
}
 
// Finds similar contacts in an
// array of contacts
function findSameContacts(arr, n) {
  // vector for storing the solution
  let sol = [];
 
  // Declare 2D adjacency matrix for mats
  let mat = new Array(n).fill().map(() => new Array(n));
 
  // visited array to keep track
  // of visited nodes
  let visited = new Array(n).fill(0);
 
  // Fill adjacency matrix
  buildGraph(arr, n, mat);
 
  // Since, we made a graph with contacts 
  // as nodes with fields as links. Two
  // nodes are linked if they represent
  // the same person. So, total number of
  // connected components and nodes in each
  // component will be our answer.
  for (let i = 0; i < n; i++) {
    if (!visited[i]) {
      DFSvisit(i, mat, visited, sol, n);
 
      // Add delimiter to separate nodes
      // of one component from other.
      sol.push(-1);
    }
  }
 
  // Print the solution
  for (let i = 0; i < sol.length; i++) {
    if (sol[i] === -1) {
      console.log("");
    } else {
      process.stdout.write(sol[i] + " ");
    }
  }
}
 
// Driver code
    let arr = [new Contact("Gaurav",
    "gaurav@gmail.com", "gaurav@gfgQA.com"),
    new Contact("Lucky", "lucky@gmail.com", "+1234567"),
    new Contact("gaurav123", "+5412312", "gaurav123@skype.com"),
    new Contact("gaurav1993", "+5412312", "gaurav@gfgQA.com"),
    new Contact("raja", "+2231210", "raja@gfg.com"),
    new Contact("bahubali", "+878312", "raja")    ];
 
    let n = arr.length;
    findSameContacts(arr, n);
 
//  This code is contributed by lokeshpotta20.


Output

0 3 2 
1 
4 5 

Time complexity: O(n2) where n is number of contacts.

Auxiliary Space : O(N)

Another Approach: (Using Union Find) 

The problem can be solved with Union Find as well. Here, we unify all the people who have at least one common contact. We need to isolate all the indices which have common contacts. To achieve this, we can maintain an array of the map of indices for each contact and unify all the indices corresponding to them. After the Union Find, we get Disjoint Sets which are distinct people.

C++14




// CPP14 program to find common contacts.
#include <bits/stdc++.h>
using namespace std;
 
// The class DSU will implement the Union Find
class DSU {
 
    vector<int> parent, size;
 
public:
    // In the constructor, we assign the each index as its
    // own parent and size as the number of contacts
    // available for that index
 
    DSU(vector<vector<string> >& contacts)
    {
        for (int i = 0; i < contacts.size(); i++) {
 
            parent.push_back(i);
 
            size.push_back(contacts[i].size());
        }
    }
 
    // Finds the set in which the element belongs. Path
    // compression is used to optimise time complexity
    int findSet(int v)
    {
 
        if (v == parent[v])
            return v;
 
        return parent[v] = findSet(parent[v]);
    }
 
    // Unifies the sets a and b where, the element belonging
    // to the smaller set is merged to the one belonging to
    // the smaller set
    void unionSet(int a, int b, vector<string>& person1,
                  vector<string>& person2)
    {
 
        if (size[a] > size[b]) {
            parent[b] = a;
            size[a] += size[b];
            for (auto contact : person2)
                person1.push_back(contact);
        }
        else {
 
            parent[a] = b;
            size[b] += size[a];
            for (auto contact : person1)
                person2.push_back(contact);
        }
    }
};
 
// Driver Code
int main()
{
    vector<vector<string> > contacts = {
        { "Gaurav", "gaurav@gmail.com",
          "gaurav@gfgQA.com" },
        { "Lucky", "lucky@gmail.com", "+1234567" },
        { "gaurav123", "+5412312", "gaurav123@skype.com" },
        { "gaurav1993", "+5412312", "gaurav@gfgQA.com" },
        { "raja", "+2231210", "raja@gfg.com" },
        { "bahubali", "+878312", "raja" }
    };
 
    // Initializing the object of DSU class
    DSU dsu(contacts);
 
    // Will contain the mapping of a contact to all the
    // indices it is present within
    unordered_map<string, vector<int> > contactToIndex;
 
    for (int index = 0; index < contacts.size(); index++) {
 
        for (auto contact : contacts[index])
            contactToIndex[contact].push_back(index);
    }
 
    // Unifies the sets of each contact if they are not
    // present in the same set
    for (auto contact : contactToIndex) {
 
        vector<int> indices = contact.second;
 
        for (int i = 0; i < indices.size() - 1; i++) {
 
            int set1 = dsu.findSet(indices[i]),
                set2 = dsu.findSet(indices[i + 1]);
 
            if (set1 != set2)
                dsu.unionSet(set1, set2, contacts[set1],
                             contacts[set2]);
        }
    }
 
    // Contains a map of all the distinct sets available
    // after union find has been completed
    unordered_map<int, vector<int> > unifiedSet;
 
    // All parents are mapped to the elements in the set
    for (int i = 0; i < contacts.size(); i++) {
 
        unifiedSet[dsu.findSet(i)].push_back(i);
    }
 
    // Printing out elements from distinct sets
    for (auto eachSet : unifiedSet) {
 
        for (auto element : eachSet.second)
            cout << element << " ";
 
        cout << endl;
    }
 
    return 0;
}


Python3




class DSU:
    def __init__(self, contacts):
        # In the constructor, we assign each index
        # as its own parent and size as the number
        #of contacts available for that index
        self.parent = [i for i in range(len(contacts))]
        self.size = [len(contacts[i]) for i in range(len(contacts))]
 
    # Finds the set in which the element belongs.
    # Path compression is used to optimize time complexity.
    def findSet(self, v):
        if v == self.parent[v]:
            return v
 
        self.parent[v] = self.findSet(self.parent[v])
        return self.parent[v]
 
    # Unifies the sets a and b where, the element
    # belonging to the smaller set is merged to
    # the one belonging to the smaller set
    def unionSet(self, a, b, person1, person2):
        if self.size[a] > self.size[b]:
            self.parent[b] = a
            self.size[a] += self.size[b]
            for contact in person2:
                person1.append(contact)
        else:
            self.parent[a] = b
            self.size[b] += self.size[a]
            for contact in person1:
                person2.append(contact)
 
# Driver Code
if __name__ == '__main__':
    contacts = [
        ["Gaurav", "gaurav@gmail.com", "gaurav@gfgQA.com"],
        ["Lucky", "lucky@gmail.com", "+1234567"],
        ["gaurav123", "+5412312", "gaurav123@skype.com"],
        ["gaurav1993", "+5412312", "gaurav@gfgQA.com"],
        ["raja", "+2231210", "raja@gfg.com"],
        ["bahubali", "+878312", "raja"]
    ]
 
    # Initializing the object of DSU class
    dsu = DSU(contacts)
 
    # Will contain the mapping of a contact to all the indices it is present within
    contactToIndex = {}
 
    for index in range(len(contacts)):
        for contact in contacts[index]:
            if contact not in contactToIndex:
                contactToIndex[contact] = []
            contactToIndex[contact].append(index)
 
    # Unifies the sets of each contact if they are not present in the same set
    for contact, indices in contactToIndex.items():
        for i in range(len(indices) - 1):
            set1 = dsu.findSet(indices[i])
            set2 = dsu.findSet(indices[i + 1])
 
            if set1 != set2:
                dsu.unionSet(set1, set2, contacts[set1], contacts[set2])
 
    # Contains a map of all the distinct sets
    # available after union find has been completed
    unifiedSet = {}
 
    # All parents are mapped to the elements in the set
    for i in range(len(contacts)):
        if dsu.parent[i] not in unifiedSet:
            unifiedSet[dsu.parent[i]] = []
        unifiedSet[dsu.parent[i]].append(i)
 
    # Printing out elements from distinct sets
    for eachSet in unifiedSet.values():
        for element in eachSet:
            print(element, end=" ")
        print()


Javascript




class DSU {
constructor(contacts) {
// In the constructor, we assign each index
// as its own parent and size as the number
//of contacts available for that index
this.parent = [...Array(contacts.length).keys()];
this.size = contacts.map(contact => contact.length);
}
 
// Finds the set in which the element belongs.
// Path compression is used to optimize time complexity.
findSet(v) {
if (v === this.parent[v]) {
return v;
}
 
 
this.parent[v] = this.findSet(this.parent[v]);
return this.parent[v];
 
}
 
// Unifies the sets a and b where, the element
// belonging to the smaller set is merged to
// the one belonging to the smaller set
unionSet(a, b, person1, person2) {
if (this.size[a] > this.size[b]) {
this.parent[b] = a;
this.size[a] += this.size[b];
person2.forEach(contact => {
person1.push(contact);
});
} else {
this.parent[a] = b;
this.size[b] += this.size[a];
person1.forEach(contact => {
person2.push(contact);
});
}
}
}
 
const contacts = [
["Gaurav", "gaurav@gmail.com", "gaurav@gfgQA.com"],
["Lucky", "lucky@gmail.com", "+1234567"],
["gaurav123", "+5412312", "gaurav123@skype.com"],
["gaurav1993", "+5412312", "gaurav@gfgQA.com"],
["raja", "+2231210", "raja@gfg.com"],
["bahubali", "+878312", "raja"]
];
 
// Initializing the object of DSU class
const dsu = new DSU(contacts);
 
// Will contain the mapping of a contact to all the indices it is present within
const contactToIndex = {};
 
for (let index = 0; index < contacts.length; index++) {
const contactList = contacts[index];
for (let i = 0; i < contactList.length; i++) {
const contact = contactList[i];
if (!contactToIndex[contact]) {
contactToIndex[contact] = [];
}
contactToIndex[contact].push(index);
}
}
 
// Unifies the sets of each contact if they are not present in the same set
for (const [contact, indices] of Object.entries(contactToIndex)) {
for (let i = 0; i < indices.length - 1; i++) {
const set1 = dsu.findSet(indices[i]);
const set2 = dsu.findSet(indices[i + 1]);
 
 
 
if (set1 !== set2) {
  dsu.unionSet(set1, set2, contacts[set1], contacts[set2]);
}
 
}
}
 
// Contains a map of all the distinct sets
// available after union find has been completed
const unifiedSet = [];
 
// All parents are mapped to the elements in the set
for (let i = 0; i < contacts.length; i++) {
  const parent = dsu.parent[i];
  if (!unifiedSet[parent]) {
    unifiedSet[parent] = [];
  }
  unifiedSet[parent].push(i);
}
 
for (const eachSet of Object.values(unifiedSet)) {
  if (eachSet) { // add a check here to ensure eachSet exists
    const elements = Array.from(eachSet);
    for (const element of elements) {
      process.stdout.write(`${element} `);
    }
    process.stdout.write("\n");
  }
}


Java




import java.util.*;
 
class GFG {
 
    List<Integer> parent;
    List<Integer> size;
 
    GFG(List<List<String>> contacts) {
 
        parent = new ArrayList<>();
        size = new ArrayList<>();
 
        for (int i = 0; i < contacts.size(); i++) {
            parent.add(i);
            size.add(contacts.get(i).size());
        }
    }
 
    int findSet(int v) {
 
        if (v == parent.get(v))
            return v;
 
        return parent.set(v, findSet(parent.get(v)));
    }
 
    void unionSet(int a, int b, List<String> person1, List<String> person2) {
 
        if (size.get(a) > size.get(b)) {
            parent.set(b, a);
            size.set(a, size.get(a) + size.get(b));
            person1.addAll(person2);
        }
        else {
            parent.set(a, b);
            size.set(b, size.get(b) + size.get(a));
            person2.addAll(person1);
        }
    }
}
 
public class Main {
 
    public static void main(String[] args) {
 
        List<List<String>> contacts = new ArrayList<>();
        contacts.add(Arrays.asList("Gaurav", "gaurav@gmail.com", "gaurav@gfgQA.com"));
        contacts.add(Arrays.asList("Lucky", "lucky@gmail.com", "+1234567"));
        contacts.add(Arrays.asList("gaurav123", "+5412312", "gaurav123@skype.com"));
        contacts.add(Arrays.asList("gaurav1993", "+5412312", "gaurav@gfgQA.com"));
        contacts.add(Arrays.asList("raja", "+2231210", "raja@gfg.com"));
        contacts.add(Arrays.asList("bahubali", "+878312", "raja"));
 
        GFG GFG = new GFG(contacts);
        Map<String, List<Integer>> contactToIndex = new HashMap<>();
 
        for (int index = 0; index < contacts.size(); index++) {
            for (String contact : contacts.get(index)) {
                if (!contactToIndex.containsKey(contact)) {
                    contactToIndex.put(contact, new ArrayList<>());
                }
                contactToIndex.get(contact).add(index);
            }
        }
 
        for (Map.Entry<String, List<Integer>> entry : contactToIndex.entrySet()) {
            List<Integer> indices = entry.getValue();
            for (int i = 0; i < indices.size() - 1; i++) {
                int set1 = GFG.findSet(indices.get(i));
                int set2 = GFG.findSet(indices.get(i + 1));
                if (set1 != set2) {
                    GFG.unionSet(set1, set2, contacts.get(set1), contacts.get(set2));
                }
            }
        }
 
        Map<Integer, List<Integer>> unifiedSet = new HashMap<>();
        for (int i = 0; i < contacts.size(); i++) {
            int parent = GFG.findSet(i);
            if (!unifiedSet.containsKey(parent)) {
                unifiedSet.put(parent, new ArrayList<>());
            }
            unifiedSet.get(parent).add(i);
        }
 
        for (Map.Entry<Integer, List<Integer>> entry : unifiedSet.entrySet()) {
            for (int element : entry.getValue()) {
                System.out.print(element + " ");
            }
            System.out.println();
        }
    }
}


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
public class GFG
{
    private List<int> parent;
    private List<int> size;
 
    public GFG(List<List<string>> contacts)
    {
        parent = new List<int>();
        size = new List<int>();
 
        for (int i = 0; i < contacts.Count; i++)
        {
            parent.Add(i);
            size.Add(contacts[i].Count);
        }
    }
 
    public int FindSet(int v)
    {
        if (v == parent[v])
            return v;
 
        return parent[v] = FindSet(parent[v]);
    }
 
    public void UnionSet(int a, int b, List<string> person1, List<string> person2)
    {
        if (size[a] > size[b])
        {
            parent[b] = a;
            size[a] += size[b];
            person1.AddRange(person2);
        }
        else
        {
            parent[a] = b;
            size[b] += size[a];
            person2.AddRange(person1);
        }
    }
}
 
public class Program
{
    public static void Main()
    {
        List<List<string>> contacts = new List<List<string>>();
        contacts.Add(new List<string> { "Gaurav", "gaurav@gmail.com", "gaurav@gfgQA.com" });
        contacts.Add(new List<string> { "Lucky", "lucky@gmail.com", "+1234567" });
        contacts.Add(new List<string> { "gaurav123", "+5412312", "gaurav123@skype.com" });
        contacts.Add(new List<string> { "gaurav1993", "+5412312", "gaurav@gfgQA.com" });
        contacts.Add(new List<string> { "raja", "+2231210", "raja@gfg.com" });
        contacts.Add(new List<string> { "bahubali", "+878312", "raja" });
 
        GFG gfg = new GFG(contacts);
        Dictionary<string, List<int>> contactToIndex = new Dictionary<string, List<int>>();
 
        for (int index = 0; index < contacts.Count; index++)
        {
            foreach (string contact in contacts[index])
            {
                if (!contactToIndex.ContainsKey(contact))
                {
                    contactToIndex.Add(contact, new List<int>());
                }
                contactToIndex[contact].Add(index);
            }
        }
 
        foreach (KeyValuePair<string, List<int>> entry in contactToIndex)
        {
            List<int> indices = entry.Value;
            for (int i = 0; i < indices.Count - 1; i++)
            {
                int set1 = gfg.FindSet(indices[i]);
                int set2 = gfg.FindSet(indices[i + 1]);
                if (set1 != set2)
                {
                    gfg.UnionSet(set1, set2, contacts[set1], contacts[set2]);
                }
            }
        }
 
        Dictionary<int, List<int>> unifiedSet = new Dictionary<int, List<int>>();
        for (int i = 0; i < contacts.Count; i++)
        {
            int parent = gfg.FindSet(i);
            if (!unifiedSet.ContainsKey(parent))
            {
                unifiedSet.Add(parent, new List<int>());
            }
            unifiedSet[parent].Add(i);
        }
 
        foreach (KeyValuePair<int, List<int>> entry in unifiedSet)
        {
            foreach (int element in entry.Value)
            {
                Console.Write(element + " ");
            }
            Console.WriteLine();
        }
    }
}


Output

4 5 
0 2 3 
1 

Time Complexity: O(N * α(N)) where N is the number of contacts and α is the Inverse Ackermann Function
Space Complexity: O(N)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads