包含每个查询的最小区间-python

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 rightilefti+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

你可能感兴趣的:(算法刷题,python,leetcode,算法刷题)