LeetCode——1851. 包含每个查询的最小区间(Minimum Interval to Include Each Query)[困难]——分析及代码(Java)

LeetCode——1851. 包含每个查询的最小区间[Minimum Interval to Include Each Query][困难]——分析及代码[Java]

  • 一、题目
  • 二、分析及代码
    • 1. 离线算法
      • (1)思路
      • (2)代码
      • (3)结果
  • 三、其他

一、题目

给你一个二维整数数组 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 <= 10^5
  • 1 <= queries.length <= 10^5
  • queries[i].length == 2
  • 1 <= lefti <= righti <= 10^7
  • 1 <= queries[j] <= 10^7

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-interval-to-include-each-query
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、分析及代码

1. 离线算法

(1)思路

在获取所有的区间和查询信息后,可按照区间的右边界和查询的大小进行降序排序,再结合优先队列(堆),顺序处理各查询时依次添加右边界符合目标值的区间、推出左边界不符合的区间,直至得到答案。

(2)代码

class Solution {
    public int[] minInterval(int[][] intervals, int[] queries) {
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>((p1, p2) -> p1[1] - p1[0] - p2[1] + p2[0]);//按区间长度排序的最小堆
        int n = intervals.length, m = queries.length;
        int[][] q = new int[m][2];//扩展queries,使排序后保留序号信息
        for (int i = 0; i < m; i++)
            q[i] = new int[]{i, queries[i]};
        Arrays.sort(q, (q1, q2) -> q2[1] - q1[1]);//从大到小排序查询
        Arrays.sort(intervals, (i1, i2) -> i2[1] - i1[1]); //按右边界从大到小排序区间
        int inter = 0;//已入堆的区间数量
        int[] ans = new int[m];//查询对应的答案
        for (int i = 0; i < m; i++) {
            int id = q[i][0], target = q[i][1];//查询序号、目标值
            while (inter < n && intervals[inter][1] >= target)//将右边界不小于当前目标值的区间入堆
                pq.add(intervals[inter++]);
            while (!pq.isEmpty() && pq.peek()[0] > target)//依次推出堆首左边界大于当前目标值的区间
                    pq.poll();
            if (pq.isEmpty())//堆空说明没有符合条件的区间
                ans[id] = -1;
            else//堆首区间即为符合条件的最小区间
                ans[id] = pq.peek()[1] - pq.peek()[0] + 1;
        }
        return ans;
    }
}

(3)结果

执行用时 :174 ms,在所有 Java 提交中击败了 45.24% 的用户;
内存消耗 :88 MB,在所有 Java 提交中击败了 24.28% 的用户。

三、其他

暂无。

你可能感兴趣的:(数据结构与算法,LeetCode,Java,题解)