leetcode第1851题,包含每个查询的最小区间
链接:https://leetcode.cn/problems/minimum-interval-to-include-each-query/
给你一个二维整数数组 intervals ,其中 intervals[i] = [lefti, righti] 表示第 i 个区间开始于 lefti 、结束于 righti(包含两侧取值,闭区间)。区间的 长度 定义为区间中包含的整数数目,更正式地表达是 r i g h t i − l e f t i + 1 right_i - left_i + 1 righti−lefti+1。
再给你一个整数数组 queries 。第 j 个查询的答案是满足 l e f t i < = q u e r i e s [ j ] < = r i g h t i left_i <= queries[j] <= right_i lefti<=queries[j]<=righti的 长度最小区间 i 的长度 。如果不存在这样的区间,那么答案是 -1 。
以数组形式返回对应查询的所有答案。
示例 1:
输入:intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5]
输出:[3,3,1,4]
解释:查询处理如下:
- Query = 2 :区间 [2,4] 是包含 2 的最小区间,答案为 4 - 2 + 1 = 3 。
- Query = 3 :区间 [2,4] 是包含 3 的最小区间,答案为 4 - 2 + 1 = 3 。
- Query = 4 :区间 [4,4] 是包含 4 的最小区间,答案为 4 - 4 + 1 = 1 。
- Query = 5 :区间 [3,6] 是包含 5 的最小区间,答案为 6 - 3 + 1 = 4 。
示例 2:
输入:intervals = [[2,3],[2,5],[1,8],[20,25]], queries = [2,19,5,22]
输出:[2,-1,4,6]
解释:查询处理如下:
- Query = 2 :区间 [2,3] 是包含 2 的最小区间,答案为 3 - 2 + 1 = 2 。
- Query = 19:不存在包含 19 的区间,答案为 -1 。
- Query = 5 :区间 [2,5] 是包含 5 的最小区间,答案为 5 - 2 + 1 = 4 。
- Query = 22:区间 [20,25] 是包含 22 的最小区间,答案为 25 - 20 + 1 = 6 。
提示:
1 <= intervals.length <= 10^5
1 <= queries.length <= 10^5
queries[i].length == 2
1 <= lefti <= righti <= 10^7
1 <= queries[j] <= 10^7
同样首先考虑暴力法,最能够出思路,那么无非就是遍历queries,对每一个查询再次遍历intervals,取最小的区间,没有就取值-1.
这样做势必会超时,提示部分已经暗示了数据相当多。
要想办法能够减少遍历的数据,第一版的暴力法queries的数据是随机的,intervals的数据也是无规律的,要想得到结果,肯定要遍历所有数据。
但是就算queries和intervals的元素顺序完全打乱,完全不会影响结果,如果存在这样一个区间的话,遍历后总能找出来。
那么不妨把queries和intervals从小到大排序,如果查询的数据已经在区间的左边了,那么后面的数据就完全没必要遍历了,这成为第二版的思路。
class Solution:
def minInterval(self, intervals: [[int]], queries: [int]) -> [int]:
n,m = len(intervals),len(queries)
intervals.sort()
queries = sorted((x,i) for i,x in enumerate(queries))
res = [-1] * m
s = 0
maxx = 10**7
for i in range(m):
a,b = queries[i]
# print(a,b)
tmp = maxx
for each in intervals:
# print(each)
if a > each[1] :
continue
if a < each[0]:
break
tmp = (each[1]-each[0]+1) if (each[1]-each[0]+1) < tmp else tmp
res[b] = tmp if tmp != maxx else -1
# print(res)
return res
这依旧会导致超时,但不妨试一试,为改进找找灵感。
对intervals的排序是先比较第一个元素,然后比较第二个元素,所以if a < each[0]可以break,因为第二个元素还是会出现乱序的情况,无法对前面区间进行舍弃,如示例1排序后[1,8] , [2,3] , [2,5],可以看出第一个区间包括了后面的区间,需要囊括进行进行计算,因此就算中间的区间不会成为答案,依旧需要从第一个开始遍历。这将导致遍历很多不需要遍历的区间。
需要一种更灵活的方式,能将后面不需要遍历的区间不算进来,前面不需要遍历的区间也不算进来。
也就是单纯的排序是不能满足要求的无法将不必要的区间及时剔除,可以采用堆排序来灵活删掉不用的区间,随着查询元素的增加,前一个元素用不到的区间,之后肯定也用不到,可以放心的丢弃。
import heapq
class Solution:
def minInterval(self, intervals: [[int]], queries: [int]) -> [int]:
n,m = len(intervals),len(queries)
intervals.sort()
queries = sorted((x,i) for i,x in enumerate(queries))
res = [-1] * m
pq = []
i =0
for x,j in queries:
while i < n and intervals[i][0] <= x:
a,b = intervals[i]
heapq.heappush(pq,(b-a+1,b))
i += 1
while pq and pq[0][1] < x:
heapq.heappop(pq)
if pq:
res[j] = pq[0][0]
return res