Bounded Range Segment Evaluator 4 — Problem Statement & Solution Guide
Problem Description
You are given a string **S** of length **N** (1 ≤ N ≤ 10^5) composed of lowercase English letters. Following the string, you receive **Q** queries (1 ≤ Q ≤ 10^5). Each query supplies two integers **L** and **R** (1 ≤ L ≤ R ≤ N) and a pattern string **P**. For every query, determine whether **P** can be obtained as a subsequence of the substring **S[L..R]** (the portion of **S** from position **L** to **R**, inclusive). Output "YES" if such a subsequence exists, otherwise output "NO". The total length of all pattern strings across all queries does not exceed 10^6.
**Input format**
- Line 1: the string **S**.
- Line 2: the integer **Q**.
- Next **Q** lines: each line contains **L R P** separated by spaces.
**Output format**
For each query, print a single line containing either "YES" or "NO".
The task requires an algorithm that processes all queries efficiently, respecting the stated time limits.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Bounded Range Segment Evaluator 4"
WHY DOES IT MATTER?
The “next‑occurrence” pattern transforms a potentially quadratic scan into a series of constant‑time jumps, enabling us to answer massive numbers of subsequence queries on a static string efficiently. It is a core technique in string algorithms, automata simulation, and range‑restricted matching.
OPTIMIZATION CHALLENGE
The key insight is to decouple the heavy work (finding next positions) from each query by doing it once in a backward pass over S. This reduces per‑query work from scanning the whole substring to merely walking through the pattern, achieving linear time in |P| regardless of substring length.
REAL-WORLD CONNECTION
Think of a distributed log system where you need to verify whether a sequence of events occurred within a specific time window. Pre‑indexing timestamps for each event type lets you jump directly to the next relevant entry, just like the next‑position table jumps to the next character.
When coding, build the next‑position table as a 2‑D int array of size (N+2)×26, fill it backwards, and use a sentinel value (N+1) to denote “no occurrence”. During a query, early‑exit as soon as the pointer exceeds R – this saves time on long patterns that already fail.
COMPLEXITY AT A GLANCE
O(N·Σ) preprocessing + O(total |P|) query time, where Σ=26; effectively O(N·26 + Σ|P|) ≈ O(N + total |P|)O(N·Σ) integers for the next table (≈ 2.6 million for Σ=26) or O(N) for position vectorsCore Theory — Why This Approach?
The problem asks whether a pattern string P appears as a subsequence inside an arbitrary substring S[L..R]. A subsequence respects order but not contiguity, so we must locate each character of P one after another within the bounded interval. A naïve scan for every query would restart from L and walk through S[L..R] character‑by‑character, yielding O(N·Q) time in the worst case – far beyond the 10^5 limits. The optimal paradigm is to preprocess the original string once, building a data structure that can jump to the next occurrence of any alphabet letter in O(1) or O(log N) time. Two classic techniques fit: (1) a 26‑column “next‑position” table where next[i][c] stores the smallest index ≥ i where character c appears, and (2) per‑character position vectors with binary search. Both reduce each query to a linear scan over |P|, independent of the substring length, turning the overall complexity into O(total |P| + N·alphabet). This preprocessing‑query separation is the hallmark of offline string‑matching problems such as “multiple subsequence queries” and is essential for scaling to 10^5 queries.
When using the next‑position table, we fill it backwards: for i from N down to 1, copy next[i+1] and then set next[i][S[i]] = i. Any lookup for the next occurrence of a character after a current pointer becomes a constant‑time array access. The query algorithm then iterates through P, repeatedly moving the pointer via next[pos][c] and checking that the returned index does not exceed R. If at any step the pointer jumps outside the interval, the answer is false; otherwise true. This method avoids repeated scans of the same region and guarantees worst‑case O(|P|) per query, which is optimal because we must at least read each character of P.
The alternative binary‑search on position vectors also respects the same asymptotic bound: each character lookup costs O(log N) but is often simpler to implement when memory is tight. Both approaches illustrate the broader algorithmic theme of “pre‑compute next occurrence” (also known as the “jump table” or “successor array”) that appears in problems like string subsequence checking, automaton simulation, and online pattern matching.
Interview Questions on This Problem
Q1How would you modify the solution if the alphabet size were up to 10^5 (e.g., Unicode characters) instead of 26?
Instead of a dense next‑position table, store for each character a sorted list of its positions in S. For each query, iterate through P and binary‑search the list to find the first occurrence ≥ current pointer and ≤ R. This keeps preprocessing O(N) and each lookup O(log N), yielding O(|P|·log N) per query, which is acceptable for large alphabets.
Q2Can you answer the queries online (i.e., without knowing all queries beforehand) while still achieving O(|P|) per query?
Yes. The next‑position table or the per‑character position vectors are built solely from S, which is known before any query arrives. Since they are static, each query can be answered independently in O(|P|) (or O(|P|·log N) with binary search) without any offline reordering.
Q3What would be the impact on time and space complexity if the total length of all pattern strings across queries summed to 10^7?
The preprocessing cost remains O(N·alphabet) or O(N) for position vectors, unchanged. The query cost becomes O(total |P|) = O(10^7) for the constant‑time next table, which is still feasible. Memory stays O(N·alphabet) ≈ 2.6 million integers for 26 letters, or O(N) for vectors, both well within limits.
Examples
Input
abacaba 3 1 7 aba 2 5 ac 3 3 b
Output
YES YES NO
Explanation: Query 1: The substring S[1..7] is "abacaba". The pattern "aba" appears as a subsequence (positions 1,3,5). Query 2: Substring S[2..5] is "baca"; "ac" is a subsequence (positions 3,4). Query 3: Substring S[3..3] is "a"; the pattern "b" cannot be formed, so the answer is NO.
Input
xyzabc 2 1 3 xy 4 6 cba
Output
YES NO
Explanation: Query 1: Substring S[1..3] is "xyz"; "xy" is a subsequence (positions 1,2). Query 2: Substring S[4..6] is "abc"; the pattern "cba" cannot be formed in order, hence NO.
Input
aaaaa 1 2 4 aaa
Output
YES
Explanation: Substring S[2..4] is "aaa". The pattern "aaa" matches exactly, so the answer is YES.
Constraints
- 1 ≤ N ≤ 10^5
- 1 ≤ Q ≤ 10^5
- 1 ≤ L ≤ R ≤ N
- The sum of |P| over all queries ≤ 10^6
- S and all P consist only of lowercase English letters
Optimal Approach & Strategy
Preprocess S to store the next occurrence of every letter at each index (or position vectors). Then answer each query by walking through P, jumping via the precomputed data, and checking that we never exceed R.
Brute Force Approach
For each query, scan S[L..R] left‑to‑right while matching characters of P one by one; if you finish P you return true, otherwise false.
Verified Code Solutions
function solution(nums) {
let sum = 0;
for (let num of nums) {
sum += num;
}
return sum;
}class Solution {
public:
int solution(vector<int>& nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
return sum;
}
};class Solution {
public int solution(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
return sum;
}
}def solution(nums):
sum = 0
for num in nums:
sum += num
return sumfunction solution(nums) {
let sum = 0;
for (let num of nums) {
sum += num;
}
return sum;
}Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.