【每日一题】1851. 包含每个查询的最小区间
1851. 包含每个查询的最小区间
题目描述
给你一个二维整数数组 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
intervals[i].length == 2
1 <= lefti <= righti <= 107
1 <= queries[j] <= 107
解题思路
思路:排序+离线查询+优先队列。通过观察,我们可以发现,查询的顺序以及区间的顺序并不会影响结果,所以我们可以先对查询以及区间排序,其中由于最后返回结果要按照初始查询顺序,故对查询排序时需要将其下标顺带存起来。对于每一个查询,遍历其所属于的长度最小的区间,那么需要满足l<=q<=r,此处相当于二维排序,我们不能一下同时处理两个维度,所以我们可以先处理l再处理r,即先将满足l<=q的收集起来,接着再从这里面去除q>r的部分,最后最小的那个区间长度即是结果。对于l部分,我们将区间按照左端点排序后就可以收集l<=q,接着我们要求最小区间,就可以使用一个小根堆,存储这些收集的l<=q,再从其中排除q>r的部分即可,此时要用到r,故可以最小堆存储区间长度和右端点即[len,r]。
class Solution {
public:
vector<int> minInterval(vector<vector<int>>& intervals, vector<int>& queries) {
// 查询顺序不会影响答案 涉及区间也不会变化
int n=intervals.size();
int m=queries.size();
// 区间按照左端点从小到大排序
// 对区间和查询值都进行排序。排序的目的是我们可以过滤掉非备选区间:即lefti > queries[j]和righti < queries[j]
sort(intervals.begin(),intervals.end());
// 定义别名
using pii=pair<int,int>;
//查询以及原始下标
vector<pii> qs;
for(int i=0;i<m;i++)
qs.emplace_back(queries[i],i);
// 查询按照从小到大排序
sort(qs.begin(),qs.end());
vector<int> ans(m,-1);
// 就和int vector<int> greater<int>一样 greater是小根堆
// [v,r]表示区间长度 右端点
priority_queue<pii,vector<pii>,greater<pii>> pq;
int i=0;
//遍历查询
for(auto &[x,j]:qs)
{
//当前遍历区间 过滤掉lefti > queries[j]
while(i<n&&intervals[i][0]<=x)
{
int a=intervals[i][0],b=intervals[i][1];
//如果区间左端点小于当前查询数则加入
pq.emplace(b-a+1,b);
i++;
}
//将右端点小于的删除 过滤掉righti < queries[j]
while(!pq.empty()&&pq.top().second<x)
pq.pop();
//最后加入满足要求的
if(!pq.empty())
ans[j]=pq.top().first;
}
return ans;
}
};
总结:对于二维数组使用sort函数,其会按照第一维度排序。priority_queue<int,vector<int>,greater<int>>是小根堆,int可以换成其他数据类型。using pii = vector<int,int>相当于使用别名。