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++ 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 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 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# 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 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. |
0 1 -1
Time Complexity: O(M * log(N))
Auxiliary Space: O(N)