Open In App

Queries to find first occurrence of a character in a given range

Improve
Improve
Like Article
Like
Save
Share
Report

Given a string S of length N and an array Q[][] of dimension M × 3 consisting of queries of type {L, R, C}, the task is to print the first index of the character C in the range [L, R], if found. Otherwise, print -1.

Examples:

Input: S= “abcabcabc”, Q[][] = { { 0, 3, ‘a’ }, { 0, 2, ‘b’ }, { 2, 4, ‘z’ } }
Output: 0 1 -1
Explanation:

  • First query: Print 0 which is the first index of character ‘a’ in the range [0, 3].
  • Second query: Print 1, which is the first index of character ‘b’ in the range [0, 2].
  • Third query: Print -1 as the character ‘z’ does not occur in the range [2, 4].

Input: S= “geeksforgeeks”, Q[][] = { { 0, 12, ‘f’ }, { 0, 2, ‘g’ }, { 6, 12, ‘f’ } }
Output: 5 0 -1
Explanation: 

  • First query: Print 5, which is the first index of character ‘f’ in the range [0, 12].
  • Second query: Print 0 which is 
    the first index of character ‘g’ in the range [0, 2].
  • Third query: Print -1 as the character ‘f’ does not occur in the range [6, 12].

Naive Approach: The simplest approach is to traverse the string over the range of indices [L, R] for each query and print the first occurrence of character C if found. Otherwise, print -1
Time Complexity: O(M * Q)
Auxiliary Space: O(1)

Efficient Approach: The above approach can be optimized by pre-storing the indices of characters in the map of vectors and using binary search to find the index in the range [L, R] in the vector of characters C. Follow the steps below to solve the problem:

  • Initialize a Map < char, vector < int > >, say V, to store indices of all occurrences of a character.
  • Traverse the string and update V.
  • Traverse the array Q:
    • If the size of V[C] is zero then print -1.
    • Otherwise, find the index by using binary search in vector V[C] i.e lower_bound(V[C].begin(), V[C].end(), L) – V[C].begin() and store it in a variable, say idx.
    • If idx = N or idx > R, then print -1.
    • Otherwise, print the index idx.

Below is the implementation of the above approach:

C++




// C++ implementation
// for the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the first occurrence
// for a given range
int firstOccurrence(string s,
                   vector<pair<pair<int, int>, char> > Q)
{
    // N = length of string
    int N = s.size();
 
    // M = length of queries
    int M = Q.size();
 
    // Stores the indices of a character
    map<char, vector<int> > v;
 
    // Traverse the string
    for (int i = 0; i < N; i++) {
 
        // Push the index i
        // into the vector[s[i]]
        v[s[i]].push_back(i);
    }
 
    // Traverse the query
    for (int i = 0; i < M; i++) {
 
        // Stores the value L
        int left = Q[i].first.first;
 
        // Stores the value R
        int right = Q[i].first.second;
 
        // Stores the character C
        char c = Q[i].second;
 
        if (v.size() == 0) {
            cout << "-1 ";
            continue;
        }
 
        // Find index >= L in
        // the vector v
        int idx
            = lower_bound(v.begin(),
                          v.end(), left)
              - v.begin();
 
        // If there is no index of C >= L
        if (idx == (int)v.size()) {
 
            cout << "-1 ";
            continue;
        }
 
        // Stores the value at idx
        idx = v[idx];
 
        // If idx > R
        if (idx > right) {
            cout << "-1 ";
        }
 
        // Otherwise
        else {
            cout << idx << " ";
        }
    }
}
 
// Driver Code
int main()
{
    string S = "abcabcabc";
    vector<pair<pair<int, int>, char> > Q
        = { { { 0, 3 }, 'a' },
            { { 0, 2 }, 'b' },
            { { 2, 4 }, 'z' } };
 
    firstOccurrence(S, Q);
    return 0;
}


Java




// Java program to implement the above approach
import java.util.*;
 
public class Main {
 
    // Function to find the first occurrence
    // for a given range
    public static void firstOccurrence(String s,
                      ArrayList<Pair<Pair<Integer, Integer>, Character>> Q)
    {
        // N = length of string
        int N = s.length();
 
        // M = length of queries
        int M = Q.size();
 
        // Stores the indices of a character
        HashMap<Character, ArrayList<Integer>> v
                = new HashMap<Character, ArrayList<Integer>>();
 
        // Traverse the string
        for (int i = 0; i < N; i++) {
 
            // Push the index i
            // into the vector[s.charAt(i)]
            char c = s.charAt(i);
            if (!v.containsKey(c)) {
                v.put(c, new ArrayList<Integer>());
            }
            v.get(c).add(i);
        }
 
        // Traverse the query
        for (int i = 0; i < M; i++) {
 
            // Stores the value L
            int left = Q.get(i).first.first;
 
            // Stores the value R
            int right = Q.get(i).first.second;
 
            // Stores the character C
            char c = Q.get(i).second;
 
            if (!v.containsKey(c) || v.get(c).size() == 0) {
                System.out.print("-1 ");
                continue;
            }
 
            // Find index >= L in
            // the vector v.get(c)
            ArrayList<Integer> charIndices = v.get(c);
            int idx = Collections.binarySearch(charIndices, left);
 
            // If there is no index of C >= L
            if (idx < 0) {
                idx = -(idx + 1);
                if (idx == charIndices.size() || charIndices.get(idx) > right) {
                    System.out.print("-1 ");
                    continue;
                }
            }
            else if (charIndices.get(idx) > right) {
                System.out.print("-1 ");
                continue;
            }
 
            // Stores the value at idx
            idx = charIndices.get(idx);
 
            // If idx > R
            if (idx > right) {
                System.out.print("-1 ");
            }
 
            // Otherwise
            else {
                System.out.print(idx + " ");
            }
        }
    }
 
    // Driver Code
    public static void main(String[] args) {
        String S = "abcabcabc";
        ArrayList<Pair<Pair<Integer, Integer>, Character>> Q
                = new ArrayList<Pair<Pair<Integer, Integer>, Character>>();
        Q.add(new Pair<Pair<Integer, Integer>, Character>(new Pair<Integer, Integer>(0, 3), 'a'));
        Q.add(new Pair<Pair<Integer, Integer>, Character>(new Pair<Integer, Integer>(0, 2), 'b'));
        Q.add(new Pair<Pair<Integer, Integer>, Character>(new Pair<Integer, Integer>(2, 4), 'z'));
 
        firstOccurrence(S, Q);
    }
}
 
class Pair<U, V> {
    public U first;
    public V second;
 
    public Pair(U first, V second) {
        this.first = first;
        this.second = second;
    }
}
 
// Contributed by adityashae15


Python3




# Python3 implementation
# for the above approach
from bisect import bisect_left
 
# Function to find the first occurrence
# for a given range
def firstOccurrence(s, Q):
   
    # N = length of string
    N = len(s)
 
    # M = length of queries
    M = len(Q)
 
    # Stores the indices of a character
    v = [[] for i in range(26)]
 
    # Traverse the string
    for i in range(N):
 
        # Push the index i
        # into the vector[s[i]]
        v[ord(s[i]) - ord('a')].append(i)
 
    # Traverse the query
    for i in range(M):
 
        # Stores the value L
        left = Q[i][0]
 
        # Stores the value R
        right = Q[i][1]
 
        # Stores the character C
        c = Q[i][2]
 
        if (len(v[ord(c) - ord('a')]) == 0):
            print ("-1")
            continue
 
        # Find index >= L in
        # the vector v
        idx = bisect_left(v[ord(c) - ord('a')], left)
 
        # If there is no index of C >= L
        if (idx == len(v[ord(c) - ord('a')])):
            print("-1 ")
            continue
 
        # Stores the value at idx
        idx = v[ord(c) - ord('a')][idx]
 
        # If idx > R
        if (idx > right):
            print ("-1 ")
             
        # Otherwise
        else:
            print(idx, end=" ")
 
# Driver Code
if __name__ == '__main__':
    S = "abcabcabc";
    Q = [ [ 0, 3 , 'a'],[ 0, 2 , 'b' ],[ 2, 4, 'z']]
 
    firstOccurrence(S, Q)
 
    # This code is contributed by mohit kumar 29.


C#




// C# program to implement the above approach
using System;
using System.Collections.Generic;
 
public class Program
{
    // Function to find the first occurrence
    // for a given range
    public static void FirstOccurrence(string s,
                      List<Tuple<Tuple<int, int>, char>> Q)
    {
        // N = length of string
        int N = s.Length;
 
        // M = length of queries
        int M = Q.Count;
 
        // Stores the indices of a character
        Dictionary<char, List<int>> v
                = new Dictionary<char, List<int>>();
 
        // Traverse the string
        for (int i = 0; i < N; i++)
        {
            // Push the index i
            // into the vector[s.charAt(i)]
            char c = s[i];
            if (!v.ContainsKey(c))
            {
                v = new List<int>();
            }
            v.Add(i);
        }
 
        // Traverse the query
        for (int i = 0; i < M; i++)
        {
            // Stores the value L
            int left = Q[i].Item1.Item1;
 
            // Stores the value R
            int right = Q[i].Item1.Item2;
 
            // Stores the character C
            char c = Q[i].Item2;
 
            if (!v.ContainsKey(c) || v.Count == 0)
            {
                Console.Write("-1 ");
                continue;
            }
 
            // Find index >= L in
            // the vector v.get(c)
            List<int> charIndices = v;
            int idx = charIndices.BinarySearch(left);
 
            // If there is no index of C >= L
            if (idx < 0)
            {
                idx = -(idx + 1);
                if (idx == charIndices.Count || charIndices[idx] > right)
                {
                    Console.Write("-1 ");
                    continue;
                }
            }
            else if (charIndices[idx] > right)
            {
                Console.Write("-1 ");
                continue;
            }
 
            // Stores the value at idx
            idx = charIndices[idx];
 
            // If idx > R
            if (idx > right)
            {
                Console.Write("-1 ");
            }
 
            // Otherwise
            else
            {
                Console.Write(idx + " ");
            }
        }
    }
 
    // Driver Code
    public static void Main()
    {
        string S = "abcabcabc";
        List<Tuple<Tuple<int, int>, char>> Q
                = new List<Tuple<Tuple<int, int>, char>>();
        Q.Add(Tuple.Create(Tuple.Create(0, 3), 'a'));
        Q.Add(Tuple.Create(Tuple.Create(0, 2), 'b'));
        Q.Add(Tuple.Create(Tuple.Create(2, 4), 'z'));
 
        FirstOccurrence(S, Q);
    }
}
 
// Contributed by adityasharmadev01


Javascript




// javascript implementation
// for the above approach
 
// lower_bound function
function lower_bound(a, x){
    let l = 0;
    let h = a.length - 1;
     
    while(l <= h){
        let m = Math.floor((l + h)/2);
         
        if(a[m] < x){
            l = m + 1;
        }
        else if(a[m] > x){
            h = m - 1;
        }
        else return l;
    }
     
    return l;
}
 
// Function to find the first occurrence
// for a given range
function firstOccurrence(s, Q)
{
    // N = length of string
    let N = s.length;
 
    // M = length of queries
    let M = Q.length;
 
    // Stores the indices of a character
    let v = {};
    // map<char, vector<int> > v;
 
    // Traverse the string
    for (let i = 0; i < N; i++) {
 
        // Push the index i
        // into the vector[s[i]]
        if(s[i] in v){
            v[s[i]].push(i);
        }
        else{
            v[s[i]] = [];
            v[s[i]].push(i);
        }
    }
 
    // Traverse the query
    for (let i = 0; i < M; i++) {
 
        // Stores the value L
        let left = Q[i][0][0];
 
        // Stores the value R
        let right = Q[i][0][1];
 
        // Stores the character C
        let c = Q[i][1];
 
        if (c in v){
             
        }
        else{
            console.log("-1 ");
            continue;
        }
 
        // Find index >= L in
        // the vector v
        let idx = lower_bound(v, left);
 
        // If there is no index of C >= L
        if (idx == v.length) {
 
            process.stdout.write("-1 ");
            continue;
        }
 
        // Stores the value at idx
        idx = v[idx];
 
        // If idx > R
        if (idx > right) {
            process.stdout.write("-1 ");
        }
 
        // Otherwise
        else {
            process.stdout.write(idx + " ");
        }
    }
}
 
// Driver Code
let S = "abcabcabc";
let Q
    = [ [ [ 0, 3 ], 'a' ],
        [ [ 0, 2 ], 'b' ],
        [ [ 2, 4 ], 'z' ] ];
 
firstOccurrence(S, Q);
  
// The code is contributed by Arushi Jindal.


 
 

Output: 

0 1 -1

 

Time Complexity: O(M * log(N))
Auxiliary Space: O(N) 



Last Updated : 16 Mar, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads