每日一练 · 包含每个查询的最小区间

110 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

一、题目描述:

给你一个二维整数数组 intervals ,其中 intervals[i] = [lefti, righti] 表示第 i 个区间开始于 lefti 、结束于 righti(包含两侧取值,闭区间)。区间的 长度 定义为区间中包含的整数数目,更正式地表达是 righti - lefti + 1 。

再给你一个整数数组 queries 。第 j 个查询的答案是满足 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 <= 105
1 <= queries.length <= 105
queries[i].length == 2
1 <= lefti <= righti <= 107
1 <= queries[j] <= 107

二、思路分析:

1、因为已经给出了所有的查询,所以可以离线处理,并不需要按照查询顺序得到结果。

2、要求包含某个查询的最短区间,那么我们可以将所有区间按照长度排序,然后从短到长遍历区间,对每个区间,看看哪些查询点落在这个区间内。而对这些查询点来说,该区间一定是包含该查询的最短区间。

3、如何得到某个区间包含哪些查询点呢?我们使用一个有序集合set保存所有查询点,这样对每一个区间[left, right]来说,set[left]和set[right]之间所有的元素x都满足set[left] <= x <= set[right]。

4、每次得到一个查询的答案,将它从集合删除,避免它被计算到了下一个更大的区间。最后剩下的点就是没有落在任何区间的点,它们的答案是-1。

三、AC 代码:

class Solution {
    public int[] minInterval(int[][] intervals, int[] queries) {
        //将区间按区间头从小到大排序
        Arrays.sort(intervals, (o1, o2) -> (o1[0] - o2[0]));
        //记录queries以及i,也就是queries[i]和i
        int[][] que = new int[queries.length][2];
        for(int i = 0; i < queries.length; ++i) {
            que[i][0] = queries[i];
            que[i][1] = i;
        }
        //将值排序,小的在前
        Arrays.sort(que, (o1, o2) -> (o1[0] - o2[0]));
        int[] res = new int[queries.length];
        Arrays.fill(res, -1);
        //优先级队列,区间长度小的区间优先,在队列头
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>((o1, o2) -> (o1[1] - o1[0] - o2[1] + o2[0]));
        //记录第几个区间,因为intervals和queries都是排好序的,所以用index记录目前走到哪里了
        int index = 0;
        for(int i = 0; i < queries.length; ++i) {
            //先把区间左边界小于等于queries[i]的区间加进去
            while(index < intervals.length && que[i][0] >= intervals[index][0]) {
                queue.offer(new int[]{intervals[index][0], intervals[index][1]});
                index += 1;
            }
            //再把区间右边界小于queries[i]的区间删除
            while(!queue.isEmpty() && queue.peek()[1] < que[i][0]) {
                queue.poll();
            }
            
         
            if(!queue.isEmpty()) {
                int[] t = queue.peek();
                res[que[i][1]] = t[1] - t[0] + 1;  
            }
        }
        return res;

    }
}

四、总结:

image.png

掘友们,解题不易,留下个赞或评论再走吧!谢啦~ 💐

希望对你有帮助

期待下次再见~