Open In App

Count of distinct characters in a substring by given range for Q queries

Last Updated : 01 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a string S consisting of lower case alphabets of size N and Q queries in the range [L, R], the task is to print the count of distinct characters in the substring by given range for each query.

Examples: 

Input: S = “geeksforgeeks”, Q[][] = {{0, 4}, {3, 7}} 
Output: 


Explanation: 
Distinct characters in substring S[0:4] are ‘g’, ‘e’, ‘k’ and ‘s’ 
Distinct characters in substring in S[3:7] are ‘k’, ‘s’ ‘f’, ‘o’ and ‘r’

Input: S = “geeksforgeeksisacomputerscienceportal”, Q[][] = {{0, 10}, {15, 18}, {12, 20}} 
Output: 


Naive Approach: The idea is to use hashing to maintain the frequency of each character in the given substring and then count the characters with a frequency equal to 1.
Below is the implementation of the above approach: 

C++




// C++ Program for Naive Approach
 
#include <bits/stdc++.h>
using namespace std;
 
void findCount(string s, int L, int R)
{
    // counter to count distinct char
    int distinct = 0;
 
    // Initializing frequency array to
    // count characters as the appear in
    // substring S[L:R]
    int frequency[26] = {};
 
    // Iterating over S[L] to S[R]
    for (int i = L; i <= R; i++) {
 
        // incrementing the count
        // of s[i] character in frequency array
        frequency[s[i] - 'a']++;
    }
 
    for (int i = 0; i < 26; i++) {
 
        // if frequency of any character is > 0
        // then increment the counter
        if (frequency[i] > 0)
            distinct++;
    }
 
    cout << distinct << endl;
}
 
/* Driver code*/
int main()
{
    string s = "geeksforgeeksisacomputerscienceportal";
    int queries = 3;
    int Q[queries][2] = { { 0, 10 },
                          { 15, 18 },
                          { 12, 20 } };
 
    for (int i = 0; i < queries; i++)
        findCount(s, Q[i][0], Q[i][1]);
 
    return 0;
}


Java




// Java program for the naive approach
class GFG{
 
static void findCount(String s, int L,
                                int R)
{
     
    // Counter to count distinct char
    int distinct = 0;
 
    // Initializing frequency array
    // to count characters as the
    // appear in subString S[L:R]
    int []frequency = new int[26];
 
    // Iterating over S[L] to S[R]
    for(int i = L; i <= R; i++)
    {
        
       // Incrementing the count of s[i]
       // character in frequency array
       frequency[s.charAt(i) - 'a']++;
    }
 
    for(int i = 0; i < 26; i++)
    {
        
       // If frequency of any character
       // is > 0 then increment the counter
       if (frequency[i] > 0)
           distinct++;
    }
    System.out.print(distinct + "\n");
}
 
// Driver code
public static void main(String[] args)
{
    String s = "geeksforgeeksisa" +
               "computerscienceportal";
    int queries = 3;
    int Q[][] = { { 0, 10 },
                  { 15, 18 },
                  { 12, 20 } };
 
    for(int i = 0; i < queries; i++)
       findCount(s, Q[i][0], Q[i][1]);
}
}
 
// This code is contributed by sapnasingh4991


Python3




# Python3 program for Naive Approach
 
def findCount(s, L, R):
     
    # Counter to count distinct char
    distinct = 0
 
    # Initializing frequency array to
    # count characters as the appear in
    # substring S[L:R]
    frequency = [0 for i in range(26)]
 
    # Iterating over S[L] to S[R]
    for i in range(L, R + 1, 1):
         
        # Incrementing the count of s[i]
        # character in frequency array
        frequency[ord(s[i]) - ord('a')] += 1
 
    for i in range(26):
         
        # If frequency of any character is > 0
        # then increment the counter
        if (frequency[i] > 0):
            distinct += 1
 
    print(distinct)
 
# Driver code
if __name__ == '__main__':
     
    s = "geeksforgeeksisacomputerscienceportal"
    queries = 3
    Q = [ [ 0, 10 ],
          [ 15, 18 ],
          [ 12, 20 ] ]
 
    for i in range(queries):
        findCount(s, Q[i][0], Q[i][1])
 
# This code is contributed by Bhupendra_Singh


C#




// C# program for the naive approach
using System;
class GFG{
 
static void findCount(String s, int L,
                                int R)
{
     
    // Counter to count distinct char
    int distinct = 0;
 
    // Initializing frequency array
    // to count characters as the
    // appear in subString S[L:R]
    int []frequency = new int[26];
 
    // Iterating over S[L] to S[R]
    for(int i = L; i <= R; i++)
    {
         
        // Incrementing the count of s[i]
        // character in frequency array
        frequency[s[i] - 'a']++;
    }
 
    for(int i = 0; i < 26; i++)
    {
             
        // If frequency of any character
        // is > 0 then increment the counter
        if (frequency[i] > 0)
            distinct++;
    }
    Console.Write(distinct + "\n");
}
 
// Driver code
public static void Main(String[] args)
{
    String s = "geeksforgeeksisa" +
               "computerscienceportal";
    int queries = 3;
    int [,]Q = {{ 0, 10 },
                { 15, 18 },
                { 12, 20 }};
 
    for(int i = 0; i < queries; i++)
    findCount(s, Q[i, 0], Q[i, 1]);
}
}
 
// This code is contributed by sapnasingh4991


Javascript




<script>
 
// Javascript Program for Naive Approach
 
function findCount(s, L, R)
{
    // counter to count distinct char
    var distinct = 0;
 
    // Initializing frequency array to
    // count characters as the appear in
    // substring S[L:R]
    var frequency = Array(26).fill(0);
 
    // Iterating over S[L] to S[R]
    for (var i = L; i <= R; i++) {
 
        // incrementing the count
        // of s[i] character in frequency array
        frequency[s[i].charCodeAt(0) - 'a'.charCodeAt(0)]++;
    }
 
    for (var i = 0; i < 26; i++) {
 
        // if frequency of any character is > 0
        // then increment the counter
        if (frequency[i] > 0)
            distinct++;
    }
 
    document.write( distinct + "<br>");
}
 
/* Driver code*/
var s = "geeksforgeeksisacomputerscienceportal";
var queries = 3;
var Q = [ [ 0, 10 ],
                      [ 15, 18 ],
                      [ 12, 20 ] ];
for (var i = 0; i < queries; i++)
    findCount(s, Q[i][0], Q[i][1]);
 
 
</script>


Output

7
4
8


Time Complexity: O(Q×N)
Auxiliary Space: O(26) ? O(1), no extra space is required, so it is a constant.

Efficient Approach: An efficient approach would be to store the position of each character as they appear in the string in an 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 first element greater than or equal L in the corresponding position vector should exist and be less than or equal to R i.e, there must be a position value between L and R denoting the presence of the alphabet in the query range.
For example:

Below is the implementation of the above approach: 

C++




// C++ Program for Efficient Approach
// to count the no. of distinct characters
// in a substring using STL
 
#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);
 
void build_position_vector(string s)
{
    for (int i = 0; i < s.size(); i++) {
 
        // inserting position of
        // character as they appear
        v[s[i] - 'a'].push_back(i);
    }
}
 
void findCount(string s, int L, int R)
{
 
    build_position_vector(s);
 
    // counter to count distinct char
    int distinct = 0;
 
    // iterating over all 26 characters
    for (int i = 0; i < 26; i++) {
 
        // Finding the first element
        // which is greater than or equal to L
        auto first = lower_bound(
            v[i].begin(),
            v[i].end(), L);
 
        // Check if first pointer exists
        // and is less than or equal to R
        if (first != v[i].end()
            && *first <= R) {
            distinct++;
        }
    }
 
    cout << distinct << endl;
}
 
/* Driver code*/
int main()
{
    string s = "geeksforgeeksisacomputerscienceportal";
    int queries = 3;
    int Q[queries][2] = { { 0, 10 },
                          { 15, 18 },
                          { 12, 20 } };
 
    for (int i = 0; i < queries; i++)
        findCount(s, Q[i][0], Q[i][1]);
 
    return 0;
}


Java




import java.util.*;
 
public class Main {
    // ArrayList of ArrayList to store
    // position of all characters
    // as they appear in string
    static ArrayList<ArrayList<Integer>> v = new ArrayList<>(26);
     
    static {
        // Initialize ArrayList for each character
        for (int i = 0; i < 26; i++) {
            v.add(new ArrayList<Integer>());
        }
    }
 
    static void buildPositionVector(String s) {
        for (int i = 0; i < s.length(); i++) {
            // inserting position of
            // character as they appear
            v.get(s.charAt(i) - 'a').add(i);
        }
    }
 
    static void findCount(String s, int L, int R) {
 
        buildPositionVector(s);
 
        // counter to count distinct char
        int distinct = 0;
 
        // iterating over all 26 characters
        for (int i = 0; i < 26; i++) {
 
            // Finding the first element
            // which is greater than or equal to L
            int first = Collections.binarySearch(v.get(i), L);
            if (first >= 0) {
                // If first pointer exists and is less than or equal to R
                if (v.get(i).get(first) <= R) {
                    distinct++;
                }
            } else {
                // If first pointer doesn't exist, calculate its position
                int insertionPoint = -first - 1;
                if (insertionPoint < v.get(i).size() && v.get(i).get(insertionPoint) <= R) {
                    distinct++;
                }
            }
        }
 
        System.out.println(distinct);
    }
 
    /* Driver code */
    public static void main(String[] args) {
        String s = "geeksforgeeksisacomputerscienceportal";
        int queries = 3;
        int[][] Q = { { 0, 10 },
                      { 15, 18 },
                      { 12, 20 } };
 
        for (int i = 0; i < queries; i++)
            findCount(s, Q[i][0], Q[i][1]);
 
    }
}


Python3




# Python program to find the number of
# distinct characters in a substring
 
import bisect
 
# vector of vector to store
# position of all characters
# as they appear in string
v = [[] for i in range(26)]
 
def build_position_vector(s):
    for i in range(len(s)):
        # inserting position of
        # character as they appear
        v[ord(s[i]) - ord('a')].append(i)
 
def findCount(s, L, R):
    build_position_vector(s)
 
    # counter to count distinct char
    distinct = 0
 
    # iterating over all 26 characters
    for i in range(26):
        # Finding the first element
        # which is greater than or equal to L
        first = bisect.bisect_left(v[i], L)
 
        # Check if first pointer exists
        # and is less than or equal to R
        if first < len(v[i]) and v[i][first] <= R:
            distinct += 1
 
    print(distinct)
 
# Driver code
s = "geeksforgeeksisacomputerscienceportal"
queries = 3
Q = [ [0, 10], [15, 18], [12, 20] ]
 
for i in range(queries):
    findCount(s, Q[i][0], Q[i][1])


C#




using System;
using System.Collections.Generic;
 
public class MainClass
{
    // List of List to store
    // position of all characters
    // as they appear in string
    static List<List<int>> v = new List<List<int>>(26);
 
    static MainClass()
    {
        // Initialize List for each character
        for (int i = 0; i < 26; i++)
        {
            v.Add(new List<int>());
        }
    }
 
    static void BuildPositionVector(string s)
    {
        for (int i = 0; i < s.Length; i++)
        {
            // inserting position of
            // character as they appear
            v[s[i] - 'a'].Add(i);
        }
    }
 
    static void FindCount(string s, int L, int R)
    {
        BuildPositionVector(s);
 
        // counter to count distinct char
        int distinct = 0;
 
        // iterating over all 26 characters
        for (int i = 0; i < 26; i++)
        {
            // Finding the first element
            // which is greater than or equal to L
            int first = v[i].BinarySearch(L);
            if (first >= 0)
            {
                // If first pointer exists and is less than or equal to R
                if (v[i][first] <= R)
                {
                    distinct++;
                }
            }
            else
            {
                // If first pointer doesn't exist, calculate its position
                int insertionPoint = ~first;
                if (insertionPoint < v[i].Count && v[i][insertionPoint] <= R)
                {
                    distinct++;
                }
            }
        }
 
        Console.WriteLine(distinct);
    }
 
    /* Driver code */
    public static void Main(string[] args)
    {
        string s = "geeksforgeeksisacomputerscienceportal";
        int queries = 3;
        int[][] Q = { new int[] { 0, 10 },
                      new int[] { 15, 18 },
                      new int[] { 12, 20 } };
 
        for (int i = 0; i < queries; i++)
        {
            FindCount(s, Q[i][0], Q[i][1]);
        }
    }
}


Javascript




// JavaScript Program for Efficient Approach
// to count the no. of distinct characters
// in a substring using array
 
// array of array to store
// position of all characters
// as they appear in string
let v = Array(26).fill(0).map(() => []);
 
// function to build vector of position for all characters
function build_position_vector(s) {
    for (let i = 0; i < s.length; i++) {
 
        // inserting position of
        // character as they appear
        v[s.charCodeAt(i) - 97].push(i);
    }
}
 
// function to find count of distinct characters in the substring
function findCount(s, L, R) {
 
    // building position vector
    build_position_vector(s);
 
    // counter to count distinct char
    let distinct = 0;
 
    // iterating over all 26 characters
    for (let i = 0; i < 26; i++) {
 
        // Finding the first element
        // which is greater than or equal to L
        const first = v[i].find(x => x >= L && x <= R);
 
        // Check if first pointer exists
        // and is less than or equal to R
        if (first !== undefined) {
            distinct++;
        }
    }
 
    console.log(distinct);
}
 
/* Driver code*/
let s = "geeksforgeeksisacomputerscienceportal";
let queries = 3;
let Q = [ [ 0, 10 ],[ 15, 18 ],[ 12, 20 ] ];
 
for (let i = 0; i < queries; i++)
    findCount(s, Q[i][0], Q[i][1]);
     
    // This code is contributed by poojaagarwal2.


Output

7
4
8


Time Complexity: O(N + Q logN)
Auxiliary Space: O(N * 26) ? O(N), where N is length of the given string.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads