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

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= “zambiatek”, 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 rangeint 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 Codeint 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 approachimport 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 approachfrom bisect import bisect_left# Function to find the first occurrence# for a given rangedef 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 Codeif __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 approachusing 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 functionfunction 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 rangefunction 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 Codelet S = "abcabcabc";let Q = [ [ [ 0, 3 ], 'a' ], [ [ 0, 2 ], 'b' ], [ [ 2, 4 ], 'z' ] ];firstOccurrence(S, Q); // The code is contributed by Arushi Jindal. |
0 1 -1
Time Complexity: O(M * log(N))
Auxiliary Space: O(N)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!



