Wednesday, July 3, 2024
HomeData ModellingData Structure & AlgorithmReplace all occurrences of X by Y or add element K in...

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:

  • If type[i]=1, insert queries1[i] (say K) to the end of the array A. The value of queries2[i] = -1 for this type of query.
  • If type[i]=2, replace all occurrences of queries1[i] (say X) with queries2[i] (say Y) in A[].

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:

  • Iterate through each query types of types[i] = 1 (for insertion in A) and types[i] = 2 for replacement of queries1[i] with queries2[i] in A.
  • For all queries types[i] = 2, if queries1[i] is present in the hashmap, then copy the vector associated to it into queries2[i] and erase whole of queries1[i]. 
  • After all the queries are performed, copy all the values of the hashmap back into the original vector A, with use of indices stored in the hashmap (keys stored as elements and vectors associated that stores indices of that element).
  • Now the original vector A is updated and is the final state of the array

Below is the implementation for the above approach:

C++14




// 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;
}


Java




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




# 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#




// 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.


Javascript




<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)

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

Last Updated :
01 Jul, 2022
Like Article
Save Article


Previous

<!–

8 Min Read | Java

–>


Next


<!–

8 Min Read | Java

–>

Nango Kalahttps://www.kala.co.za
Experienced Support Engineer with a demonstrated history of working in the information technology and services industry. Skilled in Microsoft Excel, Customer Service, Microsoft Word, Technical Support, and Microsoft Office. Strong information technology professional with a Microsoft Certificate Solutions Expert (Privet Cloud) focused in Information Technology from Broadband Collage Of Technology.
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments