Open In App

Replace all occurrences of X by Y or add element K in Array for Q queries

Given an empty array A[] & Q queries of two types 1 and 2 represented by queries1 and queries2 respectively, the task is to find the final state of the array. The queries are of the following type:

Examples:



Input: Q = 3, type = [1, 1, 2], queries1 = [1, 2, 1], queries2 = [-1, -1, 2]
Output: A = [2, 2]
Explanation: Initially A[] is empty. 
After 1st query, A = [1]. 
After 2nd query, A = [1, 2]. 
After 3rd query, A = [2, 2].

Input: Q = 5, type = [1, 1, 1, 2, 2], queries1 = [1, 2, 3, 1, 3], queries2 = [-1, -1, -1, 2, 1]
Output: A = [2, 2, 1]
Explanation: Initially A[] is empty. 
After 1st query, A = [1]. After 2nd query, A = [1, 2]. 
After 3rd query, A = [1, 2, 3]. 
After 4th query A = [2, 2, 3]. 
After 5th query, A = [2, 2, 1].



Input: Q=5, type = [1, 1, 1, 2, 2], queries1 = [1, 2, 3, 1, 2], queries2 = [-1, -1, -1, 2, 3]
Output: A = [3, 3, 3]
Explanation: Initially A[] is empty. 
After 1st query, A = [1]. After 2nd query, A = [1, 2]. 
After 3rd query, A = [1, 2, 3]. After 4th query, A = [2, 2, 3]. 
After 5th query, A = [3, 3, 3].

 

Naive Approach:

The basic way to solve the problem is to iterate through all the queries type, and for each type[i] = 1 add queries1[i] in A else if type[i]=2, find all occurrences of queries1[i] in A and replace it with queries2[i].

Time Complexity: O(Q2)
Auxiliary Space: O(1)

Efficient Approach: The problem can be solved efficiently using Hashing based on the following idea:

Use a map to store indices of the elements in the array. For  all queries of type 2, find the values to be replaced and give those indices to the replaced values.

Follow the steps below to implement the approach:

Below is the implementation for the above approach:




// C++ code to implement the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the final state of array
vector<int> processQ(int Q, vector<int> types,
                     vector<int> queries1,
                     vector<int> queries2)
{
    // Initializing an unordered map
    unordered_map<int, vector<int> > indices;
    int cnt = 0;
    for (int i = 0; i < Q; i++) {
        if (types[i] == 1) {
            indices[queries1[i]].push_back(cnt++);
        }
        else {
            for (auto& x : indices[queries1[i]])
                indices[queries2[i]].push_back(x);
            indices[queries1[i]].clear();
        }
    }
 
    vector<int> A(cnt);
    for (auto& x : indices) {
        for (auto& y : x.second)
            A[y] = x.first;
    }
 
    return A;
}
 
// Driver code
int main()
{
    vector<int> types = { 1, 1, 2 };
    vector<int> queries1 = { 1, 2, 1 };
    vector<int> queries2 = { -1, -1, 2 };
 
    // Function call
    vector<int> ans
        = processQ(types.size(), types,
                   queries1, queries2);
    for (auto& x : ans)
        cout << x << " ";
    return 0;
}




import java.util.*;
import java.io.*;
 
// Java program for the above approach
 
class GFG{
 
    // Function to find the final state of array
    static ArrayList<Integer> processQ(int Q,
                                       ArrayList<Integer> types,
                                       ArrayList<Integer> queries1,
                                       ArrayList<Integer> queries2)
    {
        // Initializing an unordered map
        HashMap<Integer, ArrayList<Integer>> indices =
          new HashMap<Integer, ArrayList<Integer>>();
 
        int cnt = 0;
        for (int i = 0 ; i < Q ; i++) {
            if (types.get(i) == 1) {
                if(!indices.containsKey(queries1.get(i))){
                    indices.put(queries1.get(i), new ArrayList<Integer>());
                }
                indices.get(queries1.get(i)).add(cnt++);
            }
            else {
                if(indices.containsKey(queries1.get(i))){
                    for (int x : indices.get(queries1.get(i))){
                        if(!indices.containsKey(queries2.get(i))){
                            indices.put(queries2.get(i), new ArrayList<Integer>());
                        }
                        indices.get(queries2.get(i)).add(x);
                    }
                    indices.get(queries1.get(i)).clear();
                }
            }
        }
 
        ArrayList<Integer> A = new ArrayList<Integer>();
        for(int i = 0 ; i < cnt ; i++){
            A.add(0);
        }
 
        for (Map.Entry<Integer, ArrayList<Integer>> x : indices.entrySet()){
            for (int y : x.getValue()){
                A.set(y, x.getKey());
            }
        }
 
        return A;
    }
 
    // Driver Code
    public static void main(String args[])
    {
        ArrayList<Integer> types = new ArrayList<Integer>(
            List.of( 1, 1, 2 )
        );
        ArrayList<Integer> queries1 = new ArrayList<Integer>(
            List.of( 1, 2, 1 )
        );
        ArrayList<Integer> queries2 = new ArrayList<Integer>(
            List.of( -1, -1, 2 )
        );
 
        // Function call
        ArrayList<Integer> ans = processQ(types.size(), types, queries1, queries2);
        for (int x : ans){
            System.out.print(x + " ");
        }
        System.out.println("");
       }
}
 
// This code is contributed by entertain2022.




# python3 code to implement the above approach
 
# Function to find the final state of array
def processQ(Q, types, queries1, queries2):
 
        # Initializing an unordered map
    indices = {}
    cnt = 0
    for i in range(0, Q):
        if (types[i] == 1):
            if queries1[i] in indices:
                indices[queries1[i]].append(cnt)
            else:
                indices[queries1[i]] = [cnt]
            cnt += 1
 
        else:
            if queries1[i] in indices:
                for x in indices[queries1[i]]:
                    if queries2[i] in indices:
                        indices[queries2[i]].append(x)
                    else:
                        indices[queries2[i]] = [x]
 
                indices[queries1[i]] = []
 
    A = [0 for _ in range(cnt)]
 
    for x in indices:
        for y in indices[x]:
            A[y] = x
 
    return A
 
# Driver code
if __name__ == "__main__":
 
    types = [1, 1, 2]
    queries1 = [1, 2, 1]
    queries2 = [-1, -1, 2]
 
    # Function call
    ans = processQ(len(types), types,
                   queries1, queries2)
    for x in ans:
        print(x, end=" ")
 
    # This code is contributed by rakeshsahni




// C# program to implement above approach
using System;
using System.Collections;
using System.Collections.Generic;
 
class GFG
{
 
  // Function to find the final state of array
  static List<int> processQ(int Q, List<int> types, List<int> queries1, List<int> queries2)
  {
    // Initializing an unordered map
    Dictionary<int, List<int>> indices = new Dictionary<int, List<int>>();
    int cnt = 0;
    for (int i = 0 ; i < Q ; i++) {
      if (types[i] == 1) {
        if(!indices.ContainsKey(queries1[i])){
          indices.Add(queries1[i], new List<int>());
        }
        indices[queries1[i]].Add(cnt++);
      }
      else {
        if(indices.ContainsKey(queries1[i])){
          foreach (int x in indices[queries1[i]]){
            if(!indices.ContainsKey(queries2[i])){
              indices.Add(queries2[i], new List<int>());
            }
            indices[queries2[i]].Add(x);
          }
          indices[queries1[i]].Clear();
        }
      }
    }
 
    List<int> A = new List<int>();
    for(int i = 0 ; i < cnt ; i++){
      A.Add(0);
    }
 
    foreach (KeyValuePair<int, List<int>> x in indices) {
      foreach (int y in x.Value){
        A[y] = x.Key;
      }
    }
 
    return A;
  }
 
  // Driver code
  public static void Main(string[] args){
 
    List<int> types = new List<int>{ 1, 1, 2 };
    List<int> queries1 = new List<int>{ 1, 2, 1 };
    List<int> queries2 = new List<int>{ -1, -1, 2 };
 
    // Function call
    List<int> ans = processQ(types.Count, types, queries1, queries2);
    foreach (int x in ans){
      Console.Write(x + " ");
 
    }
  }
}
 
// This code is contributed by subhamgoyal2014.




<script>
// JavaScript code to implement the above approach
 
// Function to find the final state of array
function processQ(Q, types, queries1, queries2)
{
 
    // Initializing an unordered object
    var indices = {};
    var cnt = 0;
    for (var i = 0; i < Q; i++)
    {
        if (types[i] == 1)
        {
            if (indices.hasOwnProperty(queries1[i]))
                indices[queries1[i]].push(cnt);
            else
                indices[queries1[i]] = [cnt];
            cnt += 1;
        }
 
        else
        {
            if (indices.hasOwnProperty(queries1[i]))
            {
                for (var j = 0; j < indices[queries1[i]].length; j++)
                {
                    var x = indices[queries1[i]][j];
                    if (indices.hasOwnProperty(queries2[i]))
                        indices[queries2[i]].push(x);
                    else
                        indices[queries2[i]] = [x];
                }
 
                indices[queries1[i]] = [];
            }
        }
    }
     
    var A = new Array(cnt).fill(0);
 
     
    for (const [keys, values] of Object.entries(indices))
    {
        for (var i = 0; i < values.length; i++)
        {
            var y = values[i];
            A[y] = keys;
        }
    }
         
    return A;
}
 
// Driver code
var types = [1, 1, 2];
var queries1 = [1, 2, 1];
var queries2 = [-1, -1, 2];
 
// Function call
var ans = processQ(types.length, types,
                   queries1, queries2);
for (var i = 0; i < ans.length; i++)
{
   document.write(ans[i] + " ");
}
 
// This code is contributed by phasing17
</script>

Output
2 2 

Time Complexity: O(Q * K) where K is the maximum size of the vector formed
Auxiliary Space: O(K)


Article Tags :