# Check if subsequences formed by given characters are same for Q queries

• Difficulty Level : Hard
• Last Updated : 13 Jul, 2022

Given an array arr[] of N strings, and Q queries where each of the queries contains some characters, the task is to check if for each query the subsequences from all the strings only made up of all the occurrences of the characters of that query are the same or not.

A subsequence is a sequence that can be derived from the given sequence by deleting some or no elements without changing the order of the remaining elements.

Examples:

Input: arr[] = {“accbad”, “abcacd”, “cacbda”}, queries[] = {{‘a’}, {‘a’, ‘b’}, {‘a’, ‘d’}, {‘b’, ‘c’, ‘d’}, {‘a’, ‘b’, ‘d’}
Output:
True
True
False
True
False
False
Explanation: All strings generate the subsequence “aa” using only the character ‘a’.
All strings generate subsequence “aba” using only the characters ‘a’ and ‘b’.
arr and arr generate subsequence “aad”, but arr generates subsequence “ada” using only the characters ‘a’ and ‘d’, and since subsequences don’t match, false is printed.
All strings generate the subsequence “bd” using only the characters ‘b’ and ‘d’
arr and arr generate subsequence “ccbd”, but arr generates subsequence “bccd” using only the characters ‘b’, ‘c’, and ‘d’, so print ‘False’.
arr and arr generate subsequence “abad”, but arr generates subsequence “abda” using only the characters ‘a’, ‘b’, and ‘d’

Input: arr[] = {“adacb”, “aacbd”}, queries[] = {{‘a’, ‘b’, ‘c’}}
Output: True.
Explanation: The subsequences are ‘aacb’ for both the strings

Naive Approach: For each query generate the subsequences containing all the occurrences of all the characters of that query and check if they are the same or not.

Time complexity: O(Q * N * M), where M is the average length of each string.
Auxiliary Space: O(1)

Efficient Approach using Memoization: This problem can be solved efficiently based on the following idea:

If the relative positions of all the characters for a query are the same in all the strings then the subsequence is common in all of them.

The relative positions of any character (say character ch), can be find out by finding the frequencies of all the characters of a query upto the index of ch. If they are the same then their relative position are also same.

Follow the steps mentioned below to implement the idea:

• Create a 3-dimensional (say elements[])array to store the frequency of each character of the strings upto each index.
• Traverse all the strings and find the frequency and store them
• Now check for the relative positions of the characters of a query.
• To implement this efficiently, iterate through the array of strings, compare the adjacent strings and do the following:
• Find the relative position of each character with respect to every other character in the English alphabet (relative position is checked by checking the frequencies of all other characters till that index).
• If they are not the same for a character (say ch) in two strings, add the characters which are causing the mismatch in a set. (mismatch means frequency counts are not the same)
• Check if the mismatches found are the same as the characters of the query.
• If so then the subsequences formed are not the same. So return false.
• After the iteration is over and a “false” is not returned, then subsequences formed are the same.

Follow the illustration below for a better understanding.

Illustration:

Say arr[] = {“adacb”, “aacbd”}, queries[] = {{‘a’, ‘b’, ‘c’}}

The frequencies of all the characters for arr and arr are shown below

arr =

arr =

For ‘a’:
=> The relative positions of the second ‘a’ are not same.
=> In the first string there is an extra ‘d’ before the 2nd ‘a’.
=> So the mismatch set is { ‘d’ }.

For ‘b’:
=> The relative positions of ‘b’ are not same.
=> In the first string there is an extra ‘d’ before it.
=> So the mismatch set is { ‘d’ }.

For ‘c’:
=> The relative positions of ‘c’ are not same.
=> In the first string there is an extra ‘d’ before it.
=> So the mismatch set is { ‘d’ }.

Now no mismatch set contains the same character as the ones present in the query. So the subsequence formed is the same for the strings.

Below is the implementation of the above approach.

## Java

 `// Java code to implement the approach`   `import` `java.io.*;` `import` `java.util.*;`   `public` `class` `SubsequenceQueries {`   `    ``// Function to check if` `    ``// the subsequences formed are the same` `    ``public` `static` `ArrayList` `    ``isPossible(``int` `N, ArrayList arr, ``int` `Q,` `               ``String queries[])` `    ``{` `        ``// For 26 letters` `        ``final` `int` `numElements = ``26``;`   `        ``// Generate prefix sums (for each letter)` `        ``// for each string` `        ``ArrayList<``int``[][]> elements` `            ``= ``new` `ArrayList<>();` `        ``for` `(``int` `i = ``0``; i < N; i++) {`   `            ``// Create a new prefix sum array` `            ``// and add it to the array list` `            ``elements.add(``new` `int``[arr.get(i).length()]` `                                ``[numElements]);` `            ``int``[][] tmp = elements.get(i);`   `            ``// Build the prefix sum` `            ``// at each position in the string` `            ``for` `(``int` `j = ``0``; j < arr.get(i).length();` `                 ``j++) {` `                ``for` `(``int` `k = ``0``; k < numElements;` `                     ``k++) {` `                    ``if` `(j != ``0``)` `                        ``tmp[j][k] = tmp[j - ``1``][k];` `                ``}`   `                ``// ASCII to int conversion` `                ``// for lowercase letters` `                ``tmp[j][arr.get(i).charAt(j) - ``97``]++;` `            ``}` `        ``}`   `        ``// Generate the set of characters` `        ``// which are necessary to remove.` `        ``// Each mapping is the set` `        ``// corresponding of characters` `        ``// which need to be removed.` `        ``// for each letter in order for a` `        ``// subsequence to be generated.` `        ``HashMap > requiredRemovals` `            ``= ``new` `HashMap<>();` `        ``for` `(``int` `i = ``0``; i < numElements; i++)` `            ``requiredRemovals.put(i, ``new` `HashSet());`   `        ``// Iterate over all the characters` `        ``// (in the alphabet in this case)` `        ``for` `(``int` `i = ``0``; i < numElements; i++) {`   `            ``// For each character,` `            ``// go through all M strings` `            ``// to generate prefix sums` `            ``for` `(``int` `j = ``1``; j < N; j++) {`   `                ``// String a stores` `                ``// the previous string (j-1)` `                ``// string b stores` `                ``// the current string (j)` `                ``String a = arr.get(j - ``1``);` `                ``String b = arr.get(j);`   `                ``// Store the prefix sums` `                ``// for strings a and b` `                ``int``[][] elements1` `                    ``= elements.get(j - ``1``);` `                ``int``[][] elements2` `                    ``= elements.get(j);`   `                ``int` `p1 = ``0``;` `                ``int` `p2 = ``0``;`   `                ``// Check if the lengths of characters` `                ``// differ; if they do, then` `                ``// no valid subsequence` `                ``// with that character can be generated.` `                ``// So for all other letters,` `                ``// add that character to its Set.` `                ``// Otherwise, check the count` `                ``// of each character` `                ``// at every position where` `                ``// letter i appears in both strings` `                ``if` `(elements1[a.length() - ``1``][i]` `                    ``!= elements2[b.length() - ``1``][i]) {` `                    ``for` `(``int` `key :` `                         ``requiredRemovals.keySet())` `                        ``requiredRemovals.get(key).add(i);` `                ``}` `                ``else` `{` `                    ``// Iterate through both strings` `                    ``// using p1 for all characters` `                    ``// in the first string` `                    ``// and p2 for all characters` `                    ``// in the second string` `                    ``while` `(p1 < a.length()` `                           ``&& p2 < b.length()) {`   `                        ``// Skip to the next occurrence of` `                        ``// character i in string a` `                        ``while` `(p1 < a.length()` `                               ``&& a.charAt(p1)` `                                          ``- ``97` `                                      ``!= i) {` `                            ``p1++;` `                        ``}`   `                        ``// Skip to the next occurrence of` `                        ``// character i in string b` `                        ``while` `(p2 < b.length()` `                               ``&& b.charAt(p2)` `                                          ``- ``97` `                                      ``!= i) {` `                            ``p2++;` `                        ``}`   `                        ``// Compare the count of each` `                        ``// character to check if they match` `                        ``// in both strings` `                        ``if` `(p1 < a.length()` `                            ``&& p2 < b.length()) {`   `                            ``// Iterate over` `                            ``// their prefix sums` `                            ``for` `(``int` `k = ``0``;` `                                 ``k < numElements;` `                                 ``k++) {` `                                ``if` `(elements1[p1][k]` `                                    ``!= elements2[p2][k])` `                                    ``requiredRemovals.get(i)` `                                        ``.add(k);` `                            ``}` `                        ``}` `                        ``p1++;` `                        ``p2++;` `                    ``}` `                ``}` `            ``}` `        ``}`   `        ``ArrayList res` `            ``= ``new` `ArrayList();`   `        ``// Read in Q queries` `        ``for` `(``int` `i = ``0``; i < Q; i++) {`   `            ``// st = new StringTokenizer(br.readLine());` `            ``// String q = st.nextToken();` `            ``Set union` `                ``= ``new` `HashSet();`   `            ``// generate a combined set of all characters` `            ``// which must be removed for a valid subsequence` `            ``// to be created with the query string` `            ``for` `(``char` `c : queries[i].toCharArray())` `                ``union.addAll(requiredRemovals.get(c - ``97``));` `            ``boolean` `ans = ``true``;`   `            ``// if there are any contradictions in the query,` `            ``// then the answer will be false` `            ``for` `(``char` `c : queries[i].toCharArray()) {` `                ``if` `(union.contains(c - ``97``))` `                    ``ans = ``false``;` `            ``}`   `            ``res.add(ans);` `        ``}` `        ``return` `res;` `    ``}`   `    ``// Driver code` `    ``public` `static` `void` `main(String[] args)` `        ``throws` `IOException` `    ``{` `        ``int` `N = ``3``;` `        ``ArrayList arr` `            ``= ``new` `ArrayList();` `        ``arr.add(``"accbad"``);` `        ``arr.add(``"abcacd"``);` `        ``arr.add(``"cacbda"``);` `        ``int` `Q = ``6``;` `        ``String queries[]` `            ``= ``new` `String[``6``];` `        ``queries[``0``] = ``"a"``;` `        ``queries[``1``] = ``"ab"``;` `        ``queries[``2``] = ``"ad"``;` `        ``queries[``3``] = ``"bd"``;` `        ``queries[``4``] = ``"bcd"``;` `        ``queries[``5``] = ``"abd"``;`   `        ``// Function call` `        ``ArrayList ans` `            ``= isPossible(N, arr, Q, queries);` `        ``for` `(``boolean` `val : ans)` `            ``System.out.println(val);` `    ``}` `}`

## C#

 `// C# program to implement above approach` `using` `System;` `using` `System.Collections.Generic;`   `class` `GFG` `{`   `    ``// For 26 letters` `    ``readonly` `public` `static` `int` `numElements = 26;`   `    ``// Function to check if` `    ``// the subsequences formed are the same` `    ``public` `static` `List<``bool``> isPossible(``int` `N, List arr, ``int` `Q, String[] queries)` `    ``{`   `        ``// Generate prefix sums (for each letter)` `        ``// for each string` `        ``List<``int``[, ]> elements = ``new` `List<``int``[, ]>();` `        ``for` `(``int` `i = 0 ; i < N ; i++) {`   `            ``// Create a new prefix sum array` `            ``// and add it to the array list` `            ``elements.Add(``new` `int``[arr[i].Length, numElements]);`   `            ``// Build the prefix sum` `            ``// at each position in the string` `            ``for` `(``int` `j = 0 ; j < arr[i].Length ; j++) {` `                ``for` `(``int` `k = 0 ; k < numElements ; k++) {` `                    ``if``(j!=0){` `                        ``elements[i][j, k] = elements[i][j - 1, k];` `                    ``}` `                ``}`   `                ``// ASCII to int conversion` `                ``// for lowercase letters` `                ``elements[i][j, ((``int``)arr[i][j] - 97)]++;` `            ``}` `        ``}`   `        ``// Generate the set of characters` `        ``// which are necessary to remove.` `        ``// Each mapping is the set` `        ``// corresponding of characters` `        ``// which need to be removed.` `        ``// for each letter in order for a` `        ``// subsequence to be generated.` `        ``SortedDictionary<``int``, SortedSet<``int``>> requiredRemovals = ``new` `SortedDictionary<``int``, SortedSet<``int``>>();` `        ``for` `(``int` `i = 0 ; i < numElements ; i++){` `            ``requiredRemovals.Add(i, ``new` `SortedSet<``int``>());` `        ``}`   `        ``// Iterate over all the characters` `        ``// (in the alphabet in this case)` `        ``for` `(``int` `i = 0 ; i < numElements ; i++) {`   `            ``// For each character,` `            ``// go through all M strings` `            ``// to generate prefix sums` `            ``for` `(``int` `j = 1 ; j < N ; j++) {`   `                ``// String a stores` `                ``// the previous string (j-1)` `                ``// string b stores` `                ``// the current string (j)` `                ``String a = arr[j - 1];` `                ``String b = arr[j];`   `                ``// Store the prefix sums` `                ``// for strings a and b` `                ``int``[, ] elements1 = elements[j - 1];` `                ``int``[, ] elements2 = elements[j];`   `                ``int` `p1 = 0;` `                ``int` `p2 = 0;`   `                ``// Check if the lengths of characters` `                ``// differ; if they do, then` `                ``// no valid subsequence` `                ``// with that character can be generated.` `                ``// So for all other letters,` `                ``// add that character to its Set.` `                ``// Otherwise, check the count` `                ``// of each character` `                ``// at every position where` `                ``// letter i appears in both strings` `                ``if` `(elements1[a.Length - 1, i] != elements2[b.Length - 1, i]) {` `                    ``foreach``( KeyValuePair<``int``, SortedSet<``int``>> pr ``in` `requiredRemovals){` `                        ``requiredRemovals[pr.Key].Add(i);` `                    ``}` `                ``}` `                ``else` `{` `                    ``// Iterate through both strings` `                    ``// using p1 for all characters` `                    ``// in the first string` `                    ``// and p2 for all characters` `                    ``// in the second string` `                    ``while` `(p1 < a.Length && p2 < b.Length) {`   `                        ``// Skip to the next occurrence of` `                        ``// character i in string a` `                        ``while` `(p1 < a.Length && ((``int``)a[p1] - 97) != i) {` `                            ``p1++;` `                        ``}`   `                        ``// Skip to the next occurrence of` `                        ``// character i in string b` `                        ``while` `(p2 < b.Length && ((``int``)b[p2] - 97) != i) {` `                            ``p2++;` `                        ``}`   `                        ``// Compare the count of each` `                        ``// character to check if they match` `                        ``// in both strings` `                        ``if` `(p1 < a.Length && p2 < b.Length) {`   `                            ``// Iterate over` `                            ``// their prefix sums` `                            ``for` `(``int` `k = 0 ; k < numElements; k++) {` `                                ``if` `(elements1[p1, k] != elements2[p2, k]){` `                                    ``requiredRemovals[i].Add(k);` `                                ``}` `                            ``}` `                        ``}` `                        ``p1++;` `                        ``p2++;` `                    ``}` `                ``}` `            ``}` `        ``}`   `        ``List<``bool``> res = ``new` `List<``bool``>();`   `        ``// Read in Q queries` `        ``for` `(``int` `i = 0; i < Q; i++) {`   `            ``// st = new StringTokenizer(br.readLine());` `            ``// String q = st.nextToken();` `            ``SortedSet<``int``> union = ``new` `SortedSet<``int``>();`   `            ``// generate a combined set of all characters` `            ``// which must be removed for a valid subsequence` `            ``// to be created with the query string` `            ``foreach` `(``char` `c ``in` `queries[i].ToCharArray()){` `                ``foreach``(``int` `x ``in` `requiredRemovals[((``int``)c - 97)]){` `                    ``union.Add(x);` `                ``}` `            ``}` `            ``bool` `ans = ``true``;`   `            ``// if there are any contradictions in the query,` `            ``// then the answer will be false` `            ``foreach` `(``char` `c ``in` `queries[i].ToCharArray()) {` `                ``if` `(union.Contains((``int``)c - 97)){` `                    ``ans = ``false``;` `                ``}` `            ``}`   `            ``res.Add(ans);` `        ``}` `        ``return` `res;` `    ``}`     `    ``// Driver Code` `    ``public` `static` `void` `Main(``string``[] args){` `        `  `        ``int` `N = 3;` `        ``List arr = ``new` `List();` `        ``arr.Add(``"accbad"``);` `        ``arr.Add(``"abcacd"``);` `        ``arr.Add(``"cacbda"``);`   `        ``int` `Q = 6;` `        ``String[] queries = ``new` `String;` `        ``queries = ``"a"``;` `        ``queries = ``"ab"``;` `        ``queries = ``"ad"``;` `        ``queries = ``"bd"``;` `        ``queries = ``"bcd"``;` `        ``queries = ``"abd"``;`   `        ``// Function call` `        ``List<``bool``> ans = isPossible(N, arr, Q, queries);` `        ``foreach``(``bool` `val ``in` `ans){` `            ``Console.Write(val + ``"\n"``);` `        ``}`   `    ``}` `}`   `// This code is contributed by subhamgoyal2014.`

Output

```true
true
false
true
false
false```

Time Complexity: O(C2 * N + Q * N)
Auxiliary Space: O(C2 * N) where C = 26

My Personal Notes arrow_drop_up
Recommended Articles
Page :