【Leetcode算法】Minimum Interval to Include Each Query 包含每个查询的最小区间

Minimum Interval to Include Each Query 包含每个查询的最小区间

问题描述:

给你一个二维整数数组 intervals ,其中 intervals[i] = [ l e f t i , r i g h t i ] [left_i, right_i] [lefti,righti] 表示第 i 个区间开始于 l e f t i left_i lefti 、结束于 r i g h t i right_i 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 < = i n t e r v a l s . l e n g t h < = 1 0 5 1 < = q u e r i e s . l e n g t h < = 1 0 5 i n t e r v a l s [ i ] . l e n g t h = = 2 1 < = l e f t i < = r i g h t i < = 1 0 7 1 < = q u e r i e s [ j ] < = 1 0 7 1 <= intervals.length <= 10^5\\ 1 <= queries.length <=10^5\\ intervals[i].length == 2\\ 1 <= left_i <= right_i <= 10^7\\ 1 <= queries[j] <= 10^7 1<=intervals.length<=1051<=queries.length<=105intervals[i].length==21<=lefti<=righti<=1071<=queries[j]<=107

分析

区间的规模最大 1 0 5 10^5 105,通常的思路,进行一次查询,必然就是遍历,与每个区间都进行比较,记录下符合条件的区间的下标,并且在过程中找到最小

单次的时间复杂度就是 O ( N ) O(N) O(N),而queries的规模最大也是 1 0 5 10^5 105,所以很明显TLE.

如果对 i n t e r v a l interval interval进行排序,以left从低到高进行排序,时间复杂度 O ( N l o g N ) O(NlogN) O(NlogN),每次查找到最后1个符合条件的位置 i d x idx idx,即 0 → i d x 0\rightarrow idx 0idx,都是符合 l e f t < = q u e r i e s [ i ] left<=queries[i] left<=queries[i],只需要在这个范围内进行遍历即可,单次的时间复杂度 O ( l o g N + M ) O( logN + M) O(logN+M).

但是在最差的情况下,依然会达到 O ( M N ) O(MN) O(MN).

其实这个思路缺少了一个环节,如果每次查询后,可以缩小后续查询的范围,就可以有加速的效果

将queries也排序从小到大,interval以left递增,并且以区间的大小从小到大排序。
对于 q u e r i e s [ i ] queries[i] queries[i],将 0 → i d x 0 \rightarrow idx 0idx,都满足 l e f t < = q u e r i e s [ i ] left<=queries[i] left<=queries[i],入优先队列。此时队列中都是left符合条件,并且区间最小的区间,但是不能保证 r i g h t > = q u e r i e s [ i ] right>=queries[i] right>=queries[i],所以需要将队首元素进行验证,如果 r i g h t < q u e r i e s [ i ] right<queries[i] right<queries[i],可以直接出队,因为 r i g h t < q u e r i e s [ i ] right<queries[i] right<queries[i],一定也 r i g h t < q u e r i e s [ j ] right<queries[j] right<queries[j].

因为queries是按照顺序出结果,所以需要记录queries的原来的顺序,然后进行索引排序。

代码

 class Solution {
    public int[] minInterval(int[][] intervals, int[] queries) {
        Integer[] qindex = new Integer[queries.length];
        for (int i = 0; i < queries.length; i++) {
            qindex[i] = i;
        }
        Arrays.sort(qindex, (i, j) -> queries[i] - queries[j]);
        Arrays.sort(intervals, (i, j) -> i[0] - j[0]);
        // scope,left,right
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> a[0] - b[0]);
        int[] res = new int[queries.length];
        Arrays.fill(res, -1);
        int i = 0;
        for (int qi : qindex) {
            while (i < intervals.length && intervals[i][0] <= queries[qi]) {
                pq.offer(new int[]{intervals[i][1] - intervals[i][0] + 1, intervals[i][0], intervals[i][1]});
                i++;
            }
            while (!pq.isEmpty() && pq.peek()[2] < queries[qi]) {
                pq.poll();
            }
            if (!pq.isEmpty()) {
                res[qi] = pq.peek()[0];
            }
        }
        return res;
    }
} 

时间复杂度 O ( M log ⁡ M + N log ⁡ N ) O(M\log M+ N\log N) O(MlogM+NlogN)

空间复杂度 O ( M + N ) O(M+N) O(M+N)

Tag

Array

Sorting

Priority Queue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Eric.Cui

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值