Query-Based Array Transformation
Last Updated : 17 Dec, 2023
Given an array arr[] of size N, initially, all the elements of arr are 0, you have to process q queries of the form "L R X" denoting that fill the array from index l to index r with the number x, the task is to print the final array after all the operations have been performed.
Examples:
Input: N = 4, queries = [[1, 3, 2], [2, 4, 6], [2, 3, 7]]
Output: [2, 7, 7, 6]
Explanation: Starting with an array of [0, 0 0 0] Starting with an array of [0, 0 0 0] lets perform some operations:
- Query [1, 3, 2]:
Add 2 to the elements, in the range from index 1 to index 3.
The updated array becomes [2, 2, 2, 0]. - Query [2, 4, 6]:
Add 6 to the elements in the range, from index 2 to index 4.
The updated array becomes [2, 6, 6, 6]. - Query [2, 3, 7]:
Adding 7 to the elements in the range from index 2 to index 3.
The updated array becomes [2, 7, 7, 6].
Input: N = 4, queries = [[1, 4, 2], [2, 3, 7], [1, 2, 3]]
Output: [3, 3, 7, 2]
Explanation: Given an array, with four elements initially set to zero, we will perform a series of operations on it. Let's go through each query step by step:
- Query [1, 4 2]:
- We add 2 to all the elements in the range from index 1 to index 4. As a result, the updated array becomes [2, 2, 2, 2].
- Query [2, 3 7]:
- Next, we add 7 to all the elements in the range from index 2 to index 3. This leads to an updated array of [2, 7, 7, 2].
- Query [1, 2, 3]:
- Finally we add 3 to all the elements in the range from index 1 to index 2. This modifies the array again. Results in [3, 3, 7, 2].
So after performing all these queries on our array of zeros and making adjustments at each step according to the given ranges and values specified within each query instruction set (from adding values like 'two' or 'seven', within specific ranges) we end up with a final updated array of [3, 3, 7, 2].
Naive Approach: The basic way to solve the problem is as follows:
The given approach uses a technique to handle a sequence of queries that involve making changes, to elements in an array. It keeps track of an array called "arr" which is initially filled with zeros and then proceeds to go through a list of queries. Each query in the format [L, R, X] guides the code to update a range [L, R], in the "arr" by assigning it the value X. The algorithm carries out these updates for each query resulting in the arr".
Follow the steps to solve the problem:
- Start by creating an array called "arr" with a size of N and initialize all its elements to zero.
- Go through each query in the "queries" list.
- For each query [L, R, X];
- Iterate through the indices from L 1 to R 1 in the "arr" array.
- Set each element within this range to the value of X.
- Once all queries have been processed, return the modified "arr" array.
Illustrations:
Lets consider an array, with four elements initially set to zero we will perform a series of operations on it. Lets go through each query step by step:
N = 4, queries = [[1, 4, 2], [2, 3, 7], [1, 2, 3]]
- Query [1, 4, 2]:
- We add 2 to all the elements in the range from index 1 to index 4. As a result the updated array becomes [2, 2, 2, 2].
- Query [2, 3, 7]:
- Next we add 7 to all the elements in the range from index 2 to index 3. This leads to an updated array of [2, 7, 7, 2].
- Query [1, 2, 3]:
- Finally we add 3 to all the elements in the range from index 1 to index 2. This modifies the array again. Results in [3, 3, 7, 2].
- So after performing all these queries on our array of zeros and making adjustments at each step according to the given ranges and values specified within each query instruction set (from adding values like 'two' or 'seven', within specific ranges) we end up with a final updated array of [3, 3, 7, 2].
Here is the implementation of the above approach:
C++ // C++ code for the above approach: #include <iostream> #include <vector> using namespace std; vector<int> DoQueries(int N, vector<vector<int> >& queries) { vector<int> arr(N, 0); for (const vector<int>& query : queries) { int L = query[0]; int R = query[1]; int X = query[2]; for (int i = L - 1; i < R; ++i) { arr[i] = X; } } return arr; } // Drivers code int main() { int N1 = 4; vector<vector<int> > queries1 = { { 1, 4, 2 }, { 2, 3, 7 }, { 1, 2, 3 } }; vector<int> result1 = DoQueries(N1, queries1); for (int value : result1) { cout << value << " "; } cout << endl; int N2 = 4; vector<vector<int> > queries2 = { { 1, 3, 2 }, { 2, 4, 6 }, { 2, 3, 7 } }; vector<int> result2 = DoQueries(N2, queries2); for (int value : result2) { cout << value << " "; } cout << endl; return 0; }
Java // Java code for the above approach import java.util.*; class GFG { public static List<Integer> doQueries(int N, List<List<Integer> > queries) { List<Integer> arr = new ArrayList<>(N); // Initialize the list with zeros for (int i = 0; i < N; i++) { arr.add(0); } for (List<Integer> query : queries) { int L = query.get(0); int R = query.get(1); int X = query.get(2); for (int i = L - 1; i < R; i++) { arr.set(i, X); } } return arr; } public static void main(String[] args) { int N1 = 4; List<List<Integer> > queries1 = List.of(List.of(1, 4, 2), List.of(2, 3, 7), List.of(1, 2, 3)); List<Integer> result1 = doQueries(N1, queries1); for (int value : result1) { System.out.print(value + " "); } System.out.println(); int N2 = 4; List<List<Integer> > queries2 = List.of(List.of(1, 3, 2), List.of(2, 4, 6), List.of(2, 3, 7)); List<Integer> result2 = doQueries(N2, queries2); for (int value : result2) { System.out.print(value + " "); } System.out.println(); } } // This code is contributed by Abhinav Mahajan // (abhinav_m22).
Python3 def do_queries(N, queries): arr = [0] * N # Initialize the list with zeros # Iterating over the queries for query in queries: L, R, X = query # Updating the array for i in range(L - 1, R): arr[i] = X return arr # Driver code if __name__ == "__main__": # Test case 1 N1 = 4 queries1 = [ [1, 4, 2], [2, 3, 7], [1, 2, 3] ] # Function call result1 = do_queries(N1, queries1) for value in result1: print(value, end=" ") print() # Test case 2 N2 = 4 queries2 = [ [1, 3, 2], [2, 4, 6], [2, 3, 7] ] # Function call result2 = do_queries(N2, queries2) for value in result2: print(value, end=" ") print()
C# // C# code for the approach using System; using System.Collections.Generic; class GFG { public static List<int> DoQueries(int N, List<List<int>> queries) { List<int> arr = new List<int>(N); // Initialize the list with zeros for (int i = 0; i < N; i++) arr.Add(0); // Iterating over the queries foreach (List<int> query in queries) { int L = query[0]; int R = query[1]; int X = query[2]; // Updating the array for (int i = L - 1; i < R; i++) arr[i] = X; } return arr; } // Driver code public static void Main(string[] args) { // Test case 1 int N1 = 4; List<List<int>> queries1 = new List<List<int>> { new List<int> { 1, 4, 2 }, new List<int> { 2, 3, 7 }, new List<int> { 1, 2, 3 } }; // Function call List<int> result1 = DoQueries(N1, queries1); foreach (int value in result1) Console.Write(value + " "); Console.WriteLine(); // Test case 2 int N2 = 4; List<List<int>> queries2 = new List<List<int>> { new List<int> { 1, 3, 2 }, new List<int> { 2, 4, 6 }, new List<int> { 2, 3, 7 } }; // Function call List<int> result2 = DoQueries(N2, queries2); foreach (int value in result2) Console.Write(value + " "); Console.WriteLine(); } } // by phasing17
JavaScript // Function to perform queries and return the resulting array function doQueries(N, queries) { // Initialize an array of length N with all elements set to 0 const arr = new Array(N).fill(0); // Iterate through each query for (const query of queries) { const L = query[0]; const R = query[1]; const X = query[2]; // Update elements in the range [L-1, R-1] to the value X for (let i = L - 1; i < R; i++) { arr[i] = X; } } return arr; } // Driver code const N1 = 4; const queries1 = [ [1, 4, 2], [2, 3, 7], [1, 2, 3] ]; const result1 = doQueries(N1, queries1); console.log(result1.join(" ")); const N2 = 4; const queries2 = [ [1, 3, 2], [2, 4, 6], [2, 3, 7] ]; const result2 = doQueries(N2, queries2); console.log(result2.join(" "));
Time Complexity Analysis:
- The time complexity, for initializing the "arr" array is O(N).
- Processing each query takes O(R. L + 1) time, where R and L represent the right and left indices of the query range.
- In the worst-case scenario, each query could potentially cover the array. Hence processing all queries would take a total time complexity of
O(q*N) where q represents the number of queries. - Overall considering both initialization and processing time complexities we can simplify it to O(q*N) where N represents the size of the array and q is the number of queries.
Space Complexity Analysis:
- The size of the "arr" array which takes up O(N) space.
- The memory required for storing all queries in a list contributes to a space complexity of O(q) where q represents the number of queries.
- Therefore when considering both factors we can conclude that overall space complexity is O(N + q).To summarize the code has a time complexity of O(q * N) and a space complexity of O(N + q) where N represents the array size and q represents the number of queries.
Efficient Approach: To solve the problem follow the below idea:
- Insert numbers from 1 to N in the set which denote indices.
- Process queries in a reverse manner and for each query find the iterators in the set for elements greater than or equal to L and elements smaller than equal to R then you update the range between the two iterators we got and then after updating we delete the values from itr1 to itr2 from set this way each index is traverse only once in all queries.
Steps to implement above Idea:
- Fill the indices" with numbers ranging from 1 to N representing the indices that are currently available.
- Next we'll go through the queries in reverse order. This way we ensure that any changes made by queries are the final changes.
- For each query retrieve and note down three things; the left bound (L), right bound (R) and value (X). These values will be crucial for updating our array. Additionally locate iterators Itr1,and Itr2 within the indices."
- Update the range between itr1 and itr2 in our array using X as their value. Afterward remove these processed indices (from itr1, to itr2) from our indices."
- Once all queries have been processed successfully our array "arr" will contain the result.
Below is the implementation in C++:
C++ // C++ code for the above approach: #include <iostream> #include <set> #include <vector> using namespace std; vector<int> DoQueries(int N, vector<vector<int> >& queries) { vector<int> arr(N, 0); set<int> indices; // Initialize the set with indices // from 1 to N for (int i = 1; i <= N; ++i) { indices.insert(i); } // Process queries in reverse order for (int q = queries.size() - 1; q >= 0; --q) { int L = queries[q][0]; int R = queries[q][1]; int X = queries[q][2]; auto itr1 = indices.lower_bound(L); auto itr2 = indices.upper_bound(R); // Update the range between itr1 and // itr2 with value X for (auto it = itr1; it != itr2; ++it) { arr[*it - 1] = X; } // Erase the processed indices // from the set indices.erase(itr1, itr2); } return arr; } // Drivers code int main() { int N1 = 4; vector<vector<int> > queries1 = { { 1, 4, 2 }, { 2, 3, 7 }, { 1, 2, 3 } }; vector<int> result1 = DoQueries(N1, queries1); for (int value : result1) { cout << value << " "; } cout << endl; int N2 = 4; vector<vector<int> > queries2 = { { 1, 3, 2 }, { 2, 4, 6 }, { 2, 3, 7 } }; vector<int> result2 = DoQueries(N2, queries2); for (int value : result2) { cout << value << " "; } cout << endl; return 0; }
Java import java.util.*; public class Queries { public static int[] doQueries(int N, int[][] queries) { int[] arr = new int[N]; Set<Integer> indices = new HashSet<>(); // Initialize the set with indices from 1 to N for (int i = 1; i <= N; ++i) { indices.add(i); } // Process queries in reverse order for (int q = queries.length - 1; q >= 0; --q) { int L = queries[q][0]; int R = queries[q][1]; int X = queries[q][2]; // Update the range between L and R with value X for (int it = L; it <= R; ++it) { if (indices.contains(it)) { arr[it - 1] = X; indices.remove(it); } } } return arr; } public static void main(String[] args) { int N1 = 4; int[][] queries1 = { { 1, 4, 2 }, { 2, 3, 7 }, { 1, 2, 3 } }; int[] result1 = doQueries(N1, queries1); System.out.println(Arrays.toString(result1)); int N2 = 4; int[][] queries2 = { { 1, 3, 2 }, { 2, 4, 6 }, { 2, 3, 7 } }; int[] result2 = doQueries(N2, queries2); System.out.println(Arrays.toString(result2)); } }
Python3 def do_queries(N, queries): arr = [0] * N indices = set(range(1, N + 1)) # Process queries in reverse order for q in reversed(queries): L, R, X = q # Update the range between L and R with value X for it in range(L, R + 1): if it in indices: arr[it - 1] = X indices.remove(it) return arr # Main function if __name__ == "__main__": N1 = 4 queries1 = [[1, 4, 2], [2, 3, 7], [1, 2, 3]] result1 = do_queries(N1, queries1) print(*result1) N2 = 4 queries2 = [[1, 3, 2], [2, 4, 6], [2, 3, 7]] result2 = do_queries(N2, queries2) print(*result2)
C# using System; using System.Collections.Generic; class Program { // Function to process queries and update the array static List<int> DoQueries(int N, List<List<int>> queries) { // Create an array of size N initialized with 0s List<int> arr = new List<int>(new int[N]); // Create a sorted set to store indices SortedSet<int> indices = new SortedSet<int>(); // Initialize the set with indices from 1 to N for (int i = 1; i <= N; ++i) { indices.Add(i); } // Process queries in reverse order for (int q = queries.Count - 1; q >= 0; --q) { // Extract L, R, and X values from the query int L = queries[q][0]; int R = queries[q][1]; int X = queries[q][2]; // Get the subset of indices between L and R (inclusive) var itr1 = indices.GetViewBetween(L, R + 1).GetEnumerator(); // Update array elements in the specified range with value X while (itr1.MoveNext()) { arr[itr1.Current - 1] = X; } // Erase the processed indices from the set indices.RemoveWhere(x => x >= L && x <= R); } return arr; } static void Main(string[] args) { int N1 = 4; List<List<int>> queries1 = new List<List<int>> { new List<int> { 1, 4, 2 }, new List<int> { 2, 3, 7 }, new List<int> { 1, 2, 3 } }; // Process queries for N1 and store the result List<int> result1 = DoQueries(N1, queries1); // Print the result of queries1 foreach (int value in result1) { Console.Write(value + " "); } Console.WriteLine(); int N2 = 4; List<List<int>> queries2 = new List<List<int>> { new List<int> { 1, 3, 2 }, new List<int> { 2, 4, 6 }, new List<int> { 2, 3, 7 } }; // Process queries for N2 and store the result List<int> result2 = DoQueries(N2, queries2); // Print the result of queries2 foreach (int value in result2) { Console.Write(value + " "); } Console.WriteLine(); } }
JavaScript function doQueries(N, queries) { let arr = new Array(N).fill(0); let indices = new Set(); // Initialize the set with indices from 1 to N for (let i = 1; i <= N; ++i) { indices.add(i); } // Process queries in reverse order for (let q = queries.length - 1; q >= 0; --q) { let L = queries[q][0]; let R = queries[q][1]; let X = queries[q][2]; // Update the range between L and R with value X for (let it = L; it <= R; ++it) { if (indices.has(it)) { arr[it - 1] = X; indices.delete(it); } } } return arr; } // Test cases let N1 = 4; let queries1 = [[1, 4, 2], [2, 3, 7], [1, 2, 3]]; let result1 = doQueries(N1, queries1); console.log(result1); let N2 = 4; let queries2 = [[1, 3, 2], [2, 4, 6], [2, 3, 7]]; let result2 = doQueries(N2, queries2); console.log(result2);
Time Complexity: O(QlogN + Q), with Q representing the number of queries and N representing the length of the arr array.
Auxiliary Space: O(N), where N is number of length of the array.
Similar Reads
Array Range Queries
The array range query problem can be defined as follows: Given an array of numbers, the array range query problem is to build a data structure that can efficiently answer queries of a particular type mentioned in terms of an interval of the indices. The specific query can be of type - maximum elemen
3 min read
Array range queries over range queries
Given an array of size n and a give set of commands of size m. The commands are enumerated from 1 to m. These commands can be of the following two types of commands: Type 1 [l r (1 <= l <= r <= n)] : Increase all elements of the array by one, whose indices belongs to the range [l, r]. In th
15+ min read
Array range queries for searching an element
Given an array of N elements and Q queries of the form L R X. For each query, you have to output if the element X exists in the array between the indices L and R(included). Prerequisite : Mo's Algorithms Examples : Input : N = 5 arr = [1, 1, 5, 4, 5] Q = 3 1 3 2 2 5 1 3 5 5 Output : No Yes Yes Expla
15+ min read
Find the final Array by updating given Ranges
Given an array arr[] consisting of N integers and an array Q[][3] consisting of M queries of the form [L, R, U], the task for each query is to xor every array element over the range [L, R] with U, After processing each query print the final array. Examples: Input: arr[] = {0, 0, 0, 0, 0, 0, 0}, Q[][
10 min read
Range Update Queries to XOR with 1 in a Binary Array.
Given a binary array arr[] of size N. The task is to answer Q queries which can be of any one type from below: Type 1 - 1 l r : Performs bitwise xor operation on all the array elements from l to r with 1. Type 2 - 2 l r : Returns the minimum distance between two elements with value 1 in a subarray [
15+ min read
Difference Array | Range update query in O(1)
You are given an integer array arr[] and a list of queries. Each query is represented as a list of integers where: [1, l, r, x]: Adds x to all elements from arr[l] to arr[r] (inclusive).[2]: Prints the current state of the array.You need to perform the queries in order. Examples : Input: arr[] = [10
11 min read
Array Rearrangement
Arrays are fundamental data structures in programming, allowing us to store and manipulate collections of related data. One common operation we may need to perform on arrays is rearranging their elements. Array rearrangement can serve various purposes, such as sorting the elements, reversing the ord
3 min read
ES6 | Array filter() Method
The Array filter() is an inbuilt method, this method creates a new array with elements that follow or pass the given criteria and condition. Few Examples have been implemented below for a better understanding of the concept Syntax: var newArray = arr.filter(callback(element[, index[, array]]) [, thi
2 min read
Associative Arrays in PHP
Associative arrays are used to store key value pairs. For example, to store the marks of different subject of a student in an array, a numerically indexed array would not be the best choice. Instead, we could use the respective subject's names as the keys in our associative array, and the value woul
3 min read
Sum of odd Array elements after each update query
Given an integer array Arr[] of length N and an array Queries[] of length Q where Queries[i] = [valuei, indexi]. For each query i, update Arr[indexi] = Arr[indexi] + valuei, then print the sum of the all the odd values of Arr[]. Examples: Input: N = 4, Arr = [1,2,3,5], Q = 4, Queries = [[1,0],[-3,1]
15+ min read