Open In App

Queries to find total number of duplicate character in range L to R in the string S

Given a string S of size N consisting of lower case alphabets and an integer Q which represents the number of queries for S. Our task is to print the number of duplicate characters in the substring L to R for all the queries Q.
Note: 1 ?N ? 106 and 1 ? Q? 106

Examples: 

Input : 
S = “geeksforgeeks”, Q = 2 
L = 1 R = 5 
L = 4 R = 8 
Output : 


Explanation: 
For the first query ‘e’ is the only duplicate character in S from range 1 to 5. 
For the second query there is no duplicate character in S.

Input : 
S = “Geekyy”, Q = 1 
L = 1 R = 6 
Output : 

Explanation: 
For the first query ‘e’ and ‘y’ are duplicate characters in S from range 1 to 6.

Naive Approach: 
The naive approach would be to maintain a frequency array of size 26, to store the count of each character. For each query, given a range [L, R] we will traverse substring S[L] to S[R] and keep counting the occurrence of each character. Now, if the frequency of any character is greater than 1 then we would add 1 to answer. 

Efficient Approach:
To solve the above problem in an efficient way we will store the position of each character as it appears in the string in a dynamic array. For each given query we will iterate over all the 26 lower case alphabets. If the current letter is in the substring S[L: R] then the next element of the first element which is greater than or equal L to in the corresponding vector should exist and be less than or equal to R
Diagram below shows how we store characters in the dynamic array:

Below is the implementation of the above approach: 




// CPP implementation to Find the total
// number of duplicate character in a
// range L to R for Q number of queries in a string S
 
#include <bits/stdc++.h>
using namespace std;
 
// Vector of vector to store
// position of all characters
// as they appear in string
vector<vector<int> > v(26);
 
// Function to store position of each character
void calculate(string s)
{
    for (int i = 0; i < s.size(); i++) {
        // Inserting position of each
        // character as they appear
        v[s[i] - 'a'].push_back(i);
    }
}
 
// Function to calculate duplicate
// characters for Q queries
void query(int L, int R)
{
    // Variable to count duplicates
    int duplicates = 0;
 
    // Iterate over all 26 characters
    for (int i = 0; i < 26; i++) {
 
        // Finding the first element which
        // is less than or equal to L
        auto first = lower_bound(v[i].begin(),
                                 v[i].end(), L - 1);
 
        // Check if first pointer exists
        // and is less than R
        if (first != v[i].end() && *first < R) {
            // Incrementing first pointer to check
            // if the next duplicate element exists
            first++;
 
            // Check if the next element exists
            // and is less than R
            if (first != v[i].end() && *first < R)
                duplicates++;
        }
    }
 
    cout << duplicates << endl;
}
 
// Driver Code
int main()
{
    string s = "geeksforgeeks";
 
    int Q = 2;
 
    int l1 = 1, r1 = 5;
    int l2 = 4, r2 = 8;
 
    calculate(s);
 
    query(l1, r1);
    query(l2, r2);
 
    return 0;
}




# Python implementation to Find the total
# number of duplicate character in a
# range L to R for Q number of queries in a string S
 
import bisect
 
# Vector of vector to store
# position of all characters
# as they appear in string
v = [[] for _ in range(26)]
 
# Function to store position of each character
def calculate(s: str) -> None:
 
    for i in range(len(s)):
        # Inserting position of each
        # character as they appear
        v[ord(s[i]) - ord('a')].append(i)
 
 
# Function to calculate duplicate
# characters for Q queries
def query(L: int, R: int) -> None:
 
    # Variable to count duplicates
    duplicates = 0
 
    # Iterate over all 26 characters
    for i in range(26):
 
        # Finding the first element which
        # is less than or equal to L
        first = bisect.bisect_left(v[i], L - 1)
 
        # Check if first pointer exists
        # and is less than R
        if (first < len(v[i]) and v[i][first] < R):
            # Incrementing first pointer to check
            # if the next duplicate element exists
            first += 1
 
            # Check if the next element exists
            # and is less than R
            if (first < len(v[i]) and v[i][first] < R):
                duplicates += 1
 
    print(duplicates)
 
 
# Driver Code
if __name__ == "__main__":
 
    s = "geeksforgeeks"
 
    Q = 2
 
    l1 = 1
    r1 = 5
    l2 = 4
    r2 = 8
 
    calculate(s)
 
    query(l1, r1)
    query(l2, r2)
 
# This code is contributed by sanjeev2552




// java implementation to Find the total
// number of duplicate character in a
// range L to R for Q number of queries in a string S
import java.util.ArrayList;
import java.util.List;
 
public class DuplicateCharacter {
    // List of List to store
    // position of all characters
    // as they appear in string
    static List<List<Integer> > v = new ArrayList<>();
    // Function to store position of each character
    static void calculate(String s)
    {
        for (int i = 0; i < 26; i++) {
            v.add(new ArrayList<>());
        }
          // Inserting position of each
        // character as they appear
        for (int i = 0; i < s.length(); i++) {
            v.get(s.charAt(i) - 'a').add(i);
        }
    }
    // Function to calculate duplicate
    // characters for Q queries
    static void query(int L, int R)
    {
        int duplicates = 0;
        for (int i = 0; i < 26; i++) {
               // Finding the first element which
            // is less than or equal to L
            int j = 0;
            while (j < v.get(i).size()
                   && v.get(i).get(j) < L) {
                j++;
            }
              // Check if first pointer exists
                // and is less than R
            if (j < v.get(i).size()
                && v.get(i).get(j) < R) {
                  // Incrementing first pointer to check
                // if the next duplicate element exists
                j++;
                  // Check if the next element exists
                // and is less than R
                if (j < v.get(i).size()
                    && v.get(i).get(j) < R) {
                    duplicates++;
                }
            }
        }
        System.out.println(duplicates);
    }
 
    public static void main(String[] args)
    {
        String s = "geeksforgeeks";
        int Q = 2;
        int l1 = 1, r1 = 5;
        int l2 = 4, r2 = 8;
        calculate(s);
        query(l1, r1);
        query(l2, r2);
    }
}




// javascript code for the above approach
 
// Function to find the index of
// the first element in a sorted
// array which is greater than or
// equal to a given value
 
function bisect_left(arr, x) {
    let lo = 0, hi = arr.length;
    while (lo < hi) {
        let mid = Math.floor((lo + hi) / 2);
        if (arr[mid] < x) {
            lo = mid + 1;
        } else {
            hi = mid;
        }
    }
    return lo;
}
 
 
 
// Vector of array to store
// position of all characters
// as they appear in string
let v = [...Array(26)].map(() => []);
 
// Function to store position of each character
function calculate(s) {
 
    for (let i = 0; i < s.length; i++) {
        // Inserting position of each
        // character as they appear
        v[s.charCodeAt(i) - 'a'.charCodeAt(0)].push(i);
    }
}
 
// Function to calculate duplicate
// characters for Q queries
function query(L, R) {
 
    // Variable to count duplicates
    let duplicates = 0;
 
    // Iterate over all 26 characters
    for (let i = 0; i < 26; i++) {
 
        // Finding the first element which
        // is less than or equal to L
        let first = bisect_left(v[i], L - 1);
 
        // Check if first pointer exists
        // and is less than R
        if (first < v[i].length && v[i][first] < R) {
            // Incrementing first pointer to check
            // if the next duplicate element exists
            first += 1;
 
            // Check if the next element exists
            // and is less than R
            if (first < v[i].length && v[i][first] < R) {
                duplicates += 1;
            }
        }
    }
 
    console.log(duplicates);
}
 
// Driver Code
let s = "geeksforgeeks";
let Q = 2;
let l1 = 1;
let r1 = 5;
let l2 = 4;
let r2 = 8;
 
calculate(s);
 
query(l1, r1);
query(l2, r2);
 
 
// This code is contributed by princekumaras




// C# program for the above approach
 
using System;
using System.Collections.Generic;
 
public class DuplicateCharacter
{
    // List of List to store
    // position of all characters
    // as they appear in string
    static List<List<int>> v = new List<List<int>>();
     
    // Function to store position of each character
    static void calculate(string s)
    {
        for (int i = 0; i < 26; i++)
        {
            v.Add(new List<int>());
        }
         
        // Inserting position of each
        // character as they appear
        for (int i = 0; i < s.Length; i++)
        {
            v[s[i] - 'a'].Add(i);
        }
    }
     
    // Function to calculate duplicate
    // characters for Q queries
    static void query(int L, int R)
    {
        int duplicates = 0;
         
        for (int i = 0; i < 26; i++)
        {
            // Finding the first element which
            // is less than or equal to L
            int j = 0;
            while (j < v[i].Count && v[i][j] < L)
            {
                j++;
            }
             
            // Check if first pointer exists
            // and is less than R
            if (j < v[i].Count && v[i][j] < R)
            {
                // Incrementing first pointer to check
                // if the next duplicate element exists
                j++;
                 
                // Check if the next element exists
                // and is less than R
                if (j < v[i].Count && v[i][j] < R)
                {
                    duplicates++;
                }
            }
        }
         
        Console.WriteLine(duplicates);
    }
     
    public static void Main(string[] args)
    {
        string s = "geeksforgeeks";
        int Q = 2;
        int l1 = 1, r1 = 5;
        int l2 = 4, r2 = 8;
        calculate(s);
        query(l1, r1);
        query(l2, r2);
    }
}
 
// This code is contributed by adityashatmfh

Output: 
1
0

 

Time Complexity: O( Q * 26 * log N)
Auxiliary Space: O(N)


Article Tags :