Open In App

Find Number of Unique Elements in an Array After each Query

Last Updated : 21 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given 2d array A[][1] of size N and array Q[][2] of size M representing M queries of type {a, b}. The task for this problem is in each query move all elements from A[a] to A[b] and print the number of unique elements in A[b].

Constraints:

  • 1 <= N, Q <= 105
  • 1 <= A[i] <= 109
  • 1 <= a, b <= N

Examples:

Input: A[][1] = {{1}, {1}, {1}, {2}, {2}, {3}}, Q[][2] = {{1, 2}, {6, 4}, {5, 1}, {3, 6}, {4, 6}}
Output: 1 2 1 1 3
Explanation:

  • For First query {1, 2} move all elements from A[1] to A[2]. A becomes {{}, {1, 1}, {1}, {2}, {2}, {3}}. Number of unique elements in A[2] is 1.
  • For Second query {6, 4} move all elements from A[6] to A[4]. A becomes {{}, {1, 1}, {1}, {2, 3}, {2}, {}}. Number of unique elements in A[4] is 2.
  • For Third query {5, 1} move all elements from A[5] to A[1]. A becomes {{2}, {1, 1}, {1}, {2, 3}, {}, {}}. Number of unique elements in A[1] is 1.
  • For Fourth query {3, 6} move all elements from A[3] to A[6]. A becomes {{2}, {1, 1}, {}, {2, 3}, {}, {1}}. Number of unique elements in A[6] is 1.
  • For Fifth query {4, 6} move all elements from A{4] to A[6]. A becomes {{2}, {1, 1}, {}, {}, {}, {1, 2, 3}}. Number of unique elements in A[6] is 3.

Input: A[][1] = {{2}, {4}, {2}, {4}, {2}}, Q[][2] = {{3, 1}, {2, 5}, {3, 2}}
Output: 1 2 0
Explanation:

  • For First query {3, 1} move all elements from A[3] to A[1]. A becomes {{2, 2}, {4}, {}, {4}, {2}}. Number of unique elements in A[1] is 1.
  • For Second query {2, 5} move all elements from A[2] to A[5]. A becomes {{2, 2}, {}, {}, {4}, {2, 4}}. Number of unique elements in A[5] is 2.
  • For Third query {3, 2} move all elements from A[3] to A[2]. A becomes {{2, 2}, {}, {}, {4}, {2, 4}}. Number of unique elements in A[2] is 0.

Efficient Approach: To solve the problem follow the below idea.

This problem is an application of the “union-by-size / small-to-large heuristic”. This algorithm depends upon fact that swapping index of sets take place in constant time, and merging a smaller set of size M into a larger set of size N takes O(MlogN). When merging sets, always move from a smaller set to a larger set. So whenever we need to move some elements from larger to smaller set we just move smaller size set elements to larger size set elements and swap their indexes.

Below are the steps for the above approach:

  • Declaring vector of sets V[N].
  • Create an HashMap for dealing with the indexes.
  • Insert all N arrays from A[][1] to N sets and initialize index map ind.
  • Iterate for M queries and for each query
  • Declare two variables x(which stores set which is to be moved) and y(which will take all incoming elements from other set).
  • whenever we find elements in the set [x] is less than set[y] we insert elements in y set and if it is greater than set[y] then we insert all element in set [x] and swap their indexes.
  • At the end of each query print the size of set V[ind[y]].

Below is the implementation of the above approach:

C++




// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to Queries to find
// number of unique elements in array
void queriesTofindUnique(int a[][1], int n, int Q[][2],
                         int m)
{
    // Creating a vector of sets
    vector<set<int> > v(n);
 
    // Creating Map to find out which index pointing towards
    // which index
    unordered_map<int, int> ind;
 
    for (int i = 0; i < n; i++) {
 
        // Insert each value in the set of perticular index
        v[i].insert(a[i][0]);
 
        // Currently each index is pointing towards itself
        ind[i] = i;
    }
    for (int i = 0; i < m; i++) {
 
        int x = Q[i][0];
        int y = Q[i][1];
        // Making index Zero Based
        --x;
        --y;
        if (v[ind[x]].size() <= v[ind[y]].size()) {
            // Transfer all elements from x to y index
            for (auto el : v[ind[x]])
                v[ind[y]].insert(el);
            // Clearing all values from 'x' index
            v[ind[x]].clear();
        }
        else {
            // Transfer all elements from y to x index
            for (auto el : v[ind[y]])
                v[ind[x]].insert(el);
            // Clearing all values from 'y' index
            v[ind[y]].clear();
            // Now index x will point towards y and y
            // towards x
            swap(ind[x], ind[y]);
        }
        // printing the size of Q[i][1]
        cout << v[ind[y]].size() << " ";
    }
    cout << "\n";
}
 
// Driver Code
int32_t main()
{
 
    // Input 1
    int N = 6, M = 5;
    int A[][1]
        = { { 1 }, { 1 }, { 1 }, { 2 }, { 2 }, { 3 } };
    int Q[][2] = {
        { 1, 2 }, { 6, 4 }, { 5, 1 }, { 3, 6 }, { 4, 6 }
    };
 
    // Function Call
    queriesTofindUnique(A, N, Q, M);
 
    return 0;
}


Java




/*code by Flutterfly */
import java.util.*;
 
public class Main {
 
    // Function to Queries to find
    // number of unique elements in array
    static void queriesToFindUnique(int[][] a, int n, int[][] Q, int m) {
        // Creating a vector of sets
        ArrayList<HashSet<Integer>> v = new ArrayList<>(n);
 
        // Creating Map to find out which index pointing towards
        // which index
        HashMap<Integer, Integer> ind = new HashMap<>();
 
        for (int i = 0; i < n; i++) {
            // Insert each value in the set of particular index
            HashSet<Integer> set = new HashSet<>();
            set.add(a[i][0]);
            v.add(set);
 
            // Currently each index is pointing towards itself
            ind.put(i, i);
        }
 
        for (int i = 0; i < m; i++) {
            int x = Q[i][0];
            int y = Q[i][1];
 
            // Making index Zero Based
            --x;
            --y;
 
            if (v.get(ind.get(x)).size() <= v.get(ind.get(y)).size()) {
                // Transfer all elements from x to y index
                for (int el : v.get(ind.get(x))) {
                    v.get(ind.get(y)).add(el);
                }
                // Clearing all values from 'x' index
                v.get(ind.get(x)).clear();
            } else {
                // Transfer all elements from y to x index
                for (int el : v.get(ind.get(y))) {
                    v.get(ind.get(x)).add(el);
                }
                // Clearing all values from 'y' index
                v.get(ind.get(y)).clear();
                // Now index x will point towards y and y
                // towards x
                Collections.swap(v, ind.get(x), ind.get(y));
            }
            // printing the size of Q[i][1]
            System.out.print(v.get(ind.get(y)).size() + " ");
        }
        System.out.println();
    }
 
    // Driver Code
    public static void main(String[] args) {
        // Input 1
        int N = 6, M = 5;
        int[][] A = {{1}, {1}, {1}, {2}, {2}, {3}};
        int[][] Q = {
            {1, 2}, {6, 4}, {5, 1}, {3, 6}, {4, 6}
        };
 
        // Function Call
        queriesToFindUnique(A, N, Q, M);
    }
}


Python3




def queries_to_find_unique(a, n, q, m):
    """
    Function to Queries to find number of unique elements in array
    """
    # Creating a list of sets
    v = [set([a[i][0]]) for i in range(n)]
 
    # Creating Map to find out which index pointing towards
    # which index
    ind = {i: i for i in range(n)}
 
    for i in range(m):
        x, y = q[i][0], q[i][1]
        # Making index Zero Based
        x -= 1
        y -= 1
 
        if len(v[ind[x]]) <= len(v[ind[y]]):
            # Transfer all elements from x to y index
            v[ind[y]].update(v[ind[x]])
            # Clearing all values from 'x' index
            v[ind[x]].clear()
        else:
            # Transfer all elements from y to x index
            v[ind[x]].update(v[ind[y]])
            # Clearing all values from 'y' index
            v[ind[y]].clear()
            # Now index x will point towards y and y towards x
            ind[x], ind[y] = ind[y], ind[x]
 
        # Printing the size of Q[i][1]
        print(len(v[ind[y]]), end=" ")
 
    print("\n")
 
 
# Driver Code
if __name__ == "__main__":
    # Input 1
    N, M = 6, 5
    A = [[1], [1], [1], [2], [2], [3]]
    Q = [[1, 2], [6, 4], [5, 1], [3, 6], [4, 6]]
 
    # Function Call
    queries_to_find_unique(A, N, Q, M)


C#




//code by Flutterfly
using System;
using System.Collections.Generic;
 
public class MainClass
{
    // Function to Queries to find
    // number of unique elements in array
    static void QueriesToFindUnique(int[][] a, int n, int[][] Q, int m)
    {
        // Creating a List of Sets
        List<HashSet<int>> v = new List<HashSet<int>>(n);
 
        // Creating Dictionary to find out which index pointing towards
        // which index
        Dictionary<int, int> ind = new Dictionary<int, int>();
 
        for (int i = 0; i < n; i++)
        {
            // Insert each value in the set of particular index
            HashSet<int> set = new HashSet<int>();
            set.Add(a[i][0]);
            v.Add(set);
 
            // Currently each index is pointing towards itself
            ind[i] = i;
        }
 
        for (int i = 0; i < m; i++)
        {
            int x = Q[i][0];
            int y = Q[i][1];
 
            // Making index Zero Based
            --x;
            --y;
 
            if (v[ind[x]].Count <= v[ind[y]].Count)
            {
                // Transfer all elements from x to y index
                foreach (int el in v[ind[x]])
                {
                    v[ind[y]].Add(el);
                }
                // Clearing all values from 'x' index
                v[ind[x]].Clear();
            }
            else
            {
                // Transfer all elements from y to x index
                foreach (int el in v[ind[y]])
                {
                    v[ind[x]].Add(el);
                }
                // Clearing all values from 'y' index
                v[ind[y]].Clear();
                // Now index x will point towards y and y
                // towards x
                int temp = ind[x];
                ind[x] = ind[y];
                ind[y] = temp;
            }
            // printing the size of Q[i][1]
            Console.Write(v[ind[y]].Count + " ");
        }
        Console.WriteLine();
    }
 
    // Driver Code
    public static void Main(string[] args)
    {
        // Input 1
        int N = 6, M = 5;
        int[][] A = { new[] { 1 }, new[] { 1 }, new[] { 1 }, new[] { 2 }, new[] { 2 }, new[] { 3 } };
        int[][] Q = {
            new[] { 1, 2 }, new[] { 6, 4 }, new[] { 5, 1 }, new[] { 3, 6 }, new[] { 4, 6 }
        };
 
        // Function Call
        QueriesToFindUnique(A, N, Q, M);
    }
}


Javascript




//code by Flutterfly
// Function to Queries to find
// number of unique elements in array
function queriesToFindUnique(a, n, Q, m) {
    // Creating an array of sets
    let v = new Array(n).fill(null).map(() => new Set());
 
    // Creating Map to find out which index pointing towards
    // which index
    let ind = new Map();
 
    for (let i = 0; i < n; i++) {
        // Insert each value in the set of particular index
        v[i].add(a[i][0]);
 
        // Currently each index is pointing towards itself
        ind.set(i, i);
    }
 
    for (let i = 0; i < m; i++) {
        let x = Q[i][0];
        let y = Q[i][1];
 
        // Making index Zero Based
        --x;
        --y;
 
        if (v[ind.get(x)].size <= v[ind.get(y)].size) {
            // Transfer all elements from x to y index
            for (let el of v[ind.get(x)]) {
                v[ind.get(y)].add(el);
            }
            // Clearing all values from 'x' index
            v[ind.get(x)].clear();
        } else {
            // Transfer all elements from y to x index
            for (let el of v[ind.get(y)]) {
                v[ind.get(x)].add(el);
            }
            // Clearing all values from 'y' index
            v[ind.get(y)].clear();
            // Now index x will point towards y and y
            // towards x
            let temp = ind.get(x);
            ind.set(x, ind.get(y));
            ind.set(y, temp);
        }
        // printing the size of Q[i][1]
        process.stdout.write(v[ind.get(y)].size + " ");
    }
    console.log();
}
 
// Driver Code
// Input 1
let N = 6, M = 5;
let A = [[1], [1], [1], [2], [2], [3]];
let Q = [
    [1, 2], [6, 4], [5, 1], [3, 6], [4, 6]
];
 
// Function Call
queriesToFindUnique(A, N, Q, M);


Output

1 2 1 1 3 




Time Complexity: O(Nlog2N)
Auxiliary Space: O(N)



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

Similar Reads