Lazy Segment Query Validator — Problem Statement & Solution Guide
Problem Description
You are tasked with validating a set of range queries against a static array of integers. Given an array arr of length N and a list of Q queries, each query specifies a range [L, R] and a target value T. For each query, you must determine if there exists a contiguous subarray within the range [L, R] whose sum is exactly equal to T. If such a subarray exists, return the length of the shortest such subarray; otherwise, return -1.
To optimize this, you will use a Binary Search on Answer Matrix approach. Specifically, for each query, you can binary search on the possible lengths of the subarray (from 1 to R - L + 1) and check if any subarray of that length within [L, R] sums to T. The check can be performed in O(1) per length using prefix sums, leading to an O(N log N) solution per query if done naively, but with preprocessing and careful binary search, you can achieve better performance.
Your task is to implement a function that processes all queries efficiently and returns the results in the same order as the input queries.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Lazy Segment Query Validator"
WHY DOES IT MATTER?
Range‑restricted two‑sum is a recurring pattern in databases, time‑series analytics, and security logs where you need to detect exact‑match windows quickly. Mastering the prefix‑sum + Mo’s algorithm combo equips you to solve any problem that reduces to “does a target appear as a difference of two values inside a sliding window?”.
OPTIMIZATION CHALLENGE
The breakthrough is realizing that you do not need to examine every pair inside the interval; you only need to know whether the complementary prefix value has already been seen. By maintaining frequencies in a mutable hash‑map while moving the window, each step becomes O(1) and the total work collapses to O((N+Q)√N).
REAL-WORLD CONNECTION
Think of a network intrusion detection system scanning a stream of packet sizes. Each query is a time window, and T is a suspicious total payload. The algorithm slides the window over the log, instantly checking if any contiguous burst of traffic matches the threat signature, just like our prefix‑sum hash map does for array queries.
When implementing Mo’s algorithm, sort queries by block of L (size ≈ √N) and then by R. Use a 64‑bit integer for prefix sums to avoid overflow, and always update the answer after adjusting the window – never recompute from scratch.
COMPLEXITY AT A GLANCE
O((N + Q) * sqrt(N))O(N)Core Theory — Why This Approach?
The heart of the problem lies in the classic prefix‑sum transformation. For any subarray \([i, j]\) the sum equals \(prefix[j] - prefix[i-1]\). Hence a query \([L,R,T]\) asks whether there exist indices \(i, j\) with \(L \le i \le j \le R\) such that \(prefix[j] = T + prefix[i-1]\). A naïve double loop would enumerate every possible \((i,j)\) pair inside the interval, leading to O(N²) per query – impossible when N and Q reach 10⁵. The optimal paradigm treats each query as a two‑sum problem confined to a sliding window of prefix values. By processing all queries offline with Mo’s algorithm we can move the left and right borders of the current window in O(1) amortised time while maintaining a hash‑map that stores frequencies of prefix sums seen so far. When the window expands to include a new right endpoint \(r\), we simply check whether \(prefix[r] - T\) already exists in the map; if it does, a valid subarray ending at \(r\) has been found. The same logic applies when shrinking the window. This yields an overall O((N+Q)·√N) time bound, which is optimal for static‑array range‑query problems where updates are absent.
Interview Questions on This Problem
Q1How would you adapt the solution if the array could be updated (point updates) between queries?
Introduce a Fenwick tree (or segment tree) that stores prefix sums and a balanced BST (or hash‑map) per block in a sqrt‑decomposition. Each update recomputes the affected block’s prefix‑sum multiset in O(√N), and queries are answered with the same Mo‑style two‑sum check across blocks, giving O(√N·logN) per operation.
Q2Explain why a simple binary‑search on a sorted list of prefix sums cannot answer a range query directly.
Binary search assumes a global ordering, but the two‑sum condition requires the two prefix values to lie within the same query interval \([L-1, R]\). A globally sorted list loses positional information, so you cannot guarantee both indices satisfy the range constraints without additional data structures.
Q3What modifications are needed to return the minimum length of a qualifying subarray instead of just existence?
Maintain, for each distinct prefix sum, the earliest index where it appears inside the current window. When checking \(prefix[r] - T\), compute the candidate length as \(r - earliestIndex\). Keep a global minimum for the current query and update it whenever a shorter valid subarray is discovered.
Examples
Input
arr = [1, 2, 3, 4, 5], queries = [[1, 5, 6], [2, 4, 7], [1, 3, 3]]
Output
[2, 2, 1]
Explanation: For query [1, 5, 6]: The subarray [1, 5] has sum 6 and length 2. No shorter subarray sums to 6. For query [2, 4, 7]: The subarray [2, 4] has sum 7 and length 2. For query [1, 3, 3]: The subarray [3] has sum 3 and length 1.
Input
arr = [5, 5, 5, 5], queries = [[1, 4, 10], [2, 3, 5], [1, 2, 11]]
Output
[2, 1, -1]
Explanation: For query [1, 4, 10]: The subarray [1, 2] has sum 10 and length 2. For query [2, 3, 5]: The subarray [2] has sum 5 and length 1. For query [1, 2, 11]: No subarray in [1, 2] sums to 11, so return -1.
Input
arr = [1, -1, 1, -1, 1], queries = [[1, 5, 1], [2, 4, 0], [1, 3, 1]]
Output
[1, 2, 1]
Explanation: For query [1, 5, 1]: The subarray [1] has sum 1 and length 1. For query [2, 4, 0]: The subarray [2, 3] has sum 0 and length 2. For query [1, 3, 1]: The subarray [1] has sum 1 and length 1.
Constraints
- 1 <= N <= 10^5
- 1 <= Q <= 10^5
- -10^9 <= arr[i] <= 10^9
- 1 <= L <= R <= N
- -10^18 <= T <= 10^18
Optimal Approach & Strategy
Transform the array to prefix sums, sort queries with Mo’s algorithm, and maintain a hash‑map of prefix frequencies while sliding the window; each add/remove is O(1) and each query is answered in O(1).
Brute Force Approach
For each query, enumerate every possible start index i from L to R and every end index j ≥ i, compute the sum, and compare to T – O(N²) per query.
Verified Code Solutions
function solution(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] === target) {
return target;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return nums[left];
}class Solution {
public:
int solution(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return target;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return nums[left];
}
};class Solution {
public int solution(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return target;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return nums[left];
}
}def solution(nums, target):
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return target
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return nums[left]function solution(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] === target) {
return target;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return nums[left];
}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.