暑期代码每日一练Day2:1851. 包含每个查询的最小区间

题目

1851. 包含每个查询的最小区间
暑期代码每日一练Day2:1851. 包含每个查询的最小区间_第1张图片
暑期代码每日一练Day2:1851. 包含每个查询的最小区间_第2张图片
暑期代码每日一练Day2:1851. 包含每个查询的最小区间_第3张图片
暑期代码每日一练Day2:1851. 包含每个查询的最小区间_第4张图片


分析

参考大佬题解:使区间与查询都有序 + 优先队列
这道题的意思是给你一个区间的集合intervals,再给你一个查询的集合intervals
区间两边都是闭合的,由两个端点组成,查询的集合里是一个个待查询的点。
问题:对于查询集合中每个待查询的点,问在区间集合中是否存在区间能够包含该点,如果没有,则查询结果表示为-1,如果有的话,求出包含该查询点的区间中最短的区间长度,查询结果保存在一个int数组中,要求查询结果的顺序与查询的顺序一致。

思路:

  1. 将待查询区间按左端点从大到小排序
  2. 将查询集合重构成由{查询点,该点在查询集合中的位置}组成的集合,并根据查询点的大小进行排序
  3. 构造一个优先队列,其中的元素是:区间的长度,区间的右端点,自定义其排序方式为按区间长度从小到大排序(保证了该队列的顶部是区间长度最小的区间)
  4. 遍历重构并排序后的新的查询集合,对于一个查询点:
  • 遍历区间集合,将左端点≤它的点放入优先队列
    对区间集合的遍历只有一次,为什么?因为当区间集合按左端点升序排序以及查询集合升序排序以后,我们放入优先队列中的左端点小于等于当前查询点的区间,对于后面的查询点,其左端点依然小于等于它们。
  • 从顶端开始遍历优先队列,将右端点比它小的点从优先队列中剔除
    当一个区间左端点和右端点都比查询点小,则不会包含该查询点,理应剔除。
    这里的剔除操作,对后续的查询点,也是有效的,因为被剔除的区间的右端点小于当前查询点,那自然也会小于后续的查询点(查询集合按升序排序)。
    这里一套操作结束以后,留在优先队列头部的自然就是包含该查询点的最小区间,且这一套操作是可以传递给下面的查询点的,这也是该算法能够降低复杂度的地方。
  1. 如果当前优先队列为空,证明我们没有找到该查询的包含区间,则根据位置索引赋值-1,否则,将区间长度赋值。

代码

class Solution {
    public int[] minInterval(int[][] intervals, int[] queries) {
        int m = intervals.length;
        int n = queries.length;
        // 将区间按左端点大小从小到大排序
        Arrays.sort(intervals, (a1,a2)->a1[0]-a2[0]);
        // 重构查询,因为最后以数组返回的顺序是和原查询的顺序一致,将查询排序会打乱这个顺序
        // 所以需要记录下原本的顺序
        int[][] qy = new int[n][2];
        for(int i=0;i<n;i++){         
            qy[i]=new int[]{queries[i],i};   //记录下索引
        }
        Arrays.sort(qy,(a1,a2)->a1[0]-a2[0]); // 将查询集合按从小到大排序
        // 结果数组
        int[] res= new int[n];  
        // 定义一个优先队列,里面的元素是(区间长度,区间右边界)
        PriorityQueue<int[]> pq = new PriorityQueue<>((a1,a2)->a1[0]-a2[0]);

        int i = 0;
        for(int j=0;j<n;j++)  //遍历查询集合
        {          //将左端点小于等于查询点的区间插入优先队列
            while(i<m&&intervals[i][0]<=qy[j][0]){
                pq.offer(new int[]{intervals[i][1]-intervals[i][0]+1,intervals[i][1]});
                i++;
            }
            // 将右端点比查询点小的区间剔除
            while(!pq.isEmpty()&&pq.peek()[1]<qy[j][0])
                pq.poll();
            // 如果当前优先队列为空,证明没找到,否则返回队列顶部的最短区间长度
            // 注意索引回去
            res[qy[j][1]] = pq.isEmpty()?-1:pq.peek()[0];
        }
        return res;
    }
}

你可能感兴趣的:(#,LeetCode刷题,总结,Java,优先队列,区间)