You are given a 2D integer array intervals, where intervals[i] = [left_i, right_i] represents the ith interval starting at left_i and ending at right_i (inclusive).
You are also given an integer array of query points queries. The result of query[j] is the length of the shortest interval i such that left_i <= queries[j] <= right_i. If no such interval exists, the result of this query is -1.
Return an array output where output[j] is the result of query[j].
Note: The length of an interval is calculated as right_i - left_i + 1.
Example 1:
Input: intervals = [[1,3],[2,3],[3,7],[6,6]], queries = [2,3,1,7,6,8]
Output: [2,2,3,5,1,-1]Explanation:
[2,3] is the smallest one containing 2, it's length is 2.[2,3] is the smallest one containing 3, it's length is 2.[1,3] is the smallest one containing 1, it's length is 3.[3,7] is the smallest one containing 7, it's length is 5.[6,6] is the smallest one containing 6, it's length is 1.Constraints:
1 <= intervals.length <= 10001 <= queries.length <= 10001 <= left_i <= right_i <= 100001 <= queries[j] <= 10000
You should aim for a solution as good or better than O(nlogn + mlogm) time and O(n + m) space, where m is the size of the array queries and n is the size of the array intervals.
A brute force approach would be to iterate through each query and, for each query, check all intervals to find the result. This would be an O(m * n) solution. Can you think of a better way? Maybe processing the queries in sorted order could help.
We sort the intervals by start value and process the queries in ascending order. Using a pointer i, we add intervals to a min-heap while their start values are less than or equal to the query, storing their end values and sizes.
The min-heap is ordered by interval size. We remove elements from the heap while the top element’s end value is less than the current query. The result for the query is the top element’s size if the heap is non-empty; otherwise, it is -1.
class Solution:
def minInterval(self, intervals: List[List[int]], queries: List[int]) -> List[int]:
n = len(intervals)
res = []
for q in queries:
cur = -1
for l, r in intervals:
if l <= q <= r:
if cur == -1 or (r - l + 1) < cur:
cur = r - l + 1
res.append(cur)
return resWhere is the length of the array and is the length of the array .
class Solution:
def minInterval(self, intervals: List[List[int]], queries: List[int]) -> List[int]:
events = []
# Create events for intervals
for idx, (start, end) in enumerate(intervals):
events.append((start, 0, end - start + 1, idx))
events.append((end, 2, end - start + 1, idx))
# Create events for queries
for i, q in enumerate(queries):
events.append((q, 1, i))
# Sort by time and type (end before query)
events.sort(key=lambda x: (x[0], x[1]))
# Min heap storing [size, index]
sizes = []
ans = [-1] * len(queries)
inactive = [False] * len(intervals)
for time, type, *rest in events:
if type == 0: # Interval start
interval_size, idx = rest
heapq.heappush(sizes, (interval_size, idx))
elif type == 2: #Interval end
idx = rest[1]
inactive[idx] = True
else: # Query
query_idx = rest[0]
while sizes and inactive[sizes[0][1]]:
heapq.heappop(sizes)
if sizes:
ans[query_idx] = sizes[0][0]
return ansWhere is the length of the array and is the length of the array .
class Solution:
def minInterval(self, intervals: List[List[int]], queries: List[int]) -> List[int]:
intervals.sort()
minHeap = []
res = {}
i = 0
for q in sorted(queries):
while i < len(intervals) and intervals[i][0] <= q:
l, r = intervals[i]
heapq.heappush(minHeap, (r - l + 1, r))
i += 1
while minHeap and minHeap[0][1] < q:
heapq.heappop(minHeap)
res[q] = minHeap[0][0] if minHeap else -1
return [res[q] for q in queries]Where is the length of the array and is the length of the array .
class SegmentTree:
def __init__(self, N):
self.n = N
self.tree = [float('inf')] * (4 * N)
self.lazy = [float('inf')] * (4 * N)
def propagate(self, treeidx, lo, hi):
if self.lazy[treeidx] != float('inf'):
self.tree[treeidx] = min(self.tree[treeidx], self.lazy[treeidx])
if lo != hi:
self.lazy[2 * treeidx + 1] = min(self.lazy[2 * treeidx + 1], self.lazy[treeidx])
self.lazy[2 * treeidx + 2] = min(self.lazy[2 * treeidx + 2], self.lazy[treeidx])
self.lazy[treeidx] = float('inf')
def update(self, treeidx, lo, hi, left, right, val):
self.propagate(treeidx, lo, hi)
if lo > right or hi < left:
return
if lo >= left and hi <= right:
self.lazy[treeidx] = min(self.lazy[treeidx], val)
self.propagate(treeidx, lo, hi)
return
mid = (lo + hi) // 2
self.update(2 * treeidx + 1, lo, mid, left, right, val)
self.update(2 * treeidx + 2, mid + 1, hi, left, right, val)
self.tree[treeidx] = min(self.tree[2 * treeidx + 1], self.tree[2 * treeidx + 2])
def query(self, treeidx, lo, hi, idx):
self.propagate(treeidx, lo, hi)
if lo == hi:
return self.tree[treeidx]
mid = (lo + hi) // 2
if idx <= mid:
return self.query(2 * treeidx + 1, lo, mid, idx)
else:
return self.query(2 * treeidx + 2, mid + 1, hi, idx)
def update_range(self, left, right, val):
self.update(0, 0, self.n - 1, left, right, val)
def query_point(self, idx):
return self.query(0, 0, self.n - 1, idx)
class Solution:
def minInterval(self, intervals: List[List[int]], queries: List[int]) -> List[int]:
points = []
for interval in intervals:
points.append(interval[0])
points.append(interval[1])
for q in queries:
points.append(q)
# Compress the coordinates
points = sorted(set(points))
compress = {points[i]: i for i in range(len(points))}
# Lazy Segment Tree
segTree = SegmentTree(len(points))
for interval in intervals:
start = compress[interval[0]]
end = compress[interval[1]]
length = interval[1] - interval[0] + 1
segTree.update_range(start, end, length)
ans = []
for q in queries:
idx = compress[q]
# query for minSize
res = segTree.query_point(idx)
ans.append(res if res != float('inf') else -1)
return ansWhere is the length of the array , is the length of the array and is the number of unique points.