链接:
1851. 包含每个查询的最小区间
题意:
给定一个区间二维数组,有N个[L,R]
区间(闭区间)
给定一组查询,有M个正整数
,求存在于区间数组中的最小R-L+1
满足L<=M[i]<=R
解:
本来看标签有个扫描线,想写个差分,然后排序查询整O(1)查询的,没写出来QWQ,也不知道有没有这种整法
优先队列倒是会写
因为每个查询独立且一次性给出,所以可以离线查询,对查询数组从小到大排序(记得保留原序),称为NM
对于一个左端点L小于NM[i]
的区间,对于NM[i]
以及其后面的查询都是可能合法的区间,因为NM递增
对于一个右端点R小于NM[i]
的区间,对于NM[i]
以及其后面的查询都是一定非法的区间,因为NM递增
所以当查询从小到大时,L若从小到大,则对于这个查询合法则对后面的所以查询皆合法,R若从小到大,则对这个查询非法则对后面的所以查询皆非法
那么步骤就是,排序区间数组和查询数组,双指针遍历,对于每个查询:
将所有NM[i]>=L,加入一个容器,即步骤1,得到一个所有可能合法区间
将容器内所有NM[i]>R
,剔除,即步骤2,可以得到一个该值的所有一定合法区间
最后选择容器中最小的R-L+1
,得到该查询的答案。难点就在于在这个容器中删除NM[i]>R
这时候就要使用我们的优先队列了,使小的R-L+1
在前面,在这基础上,小的R在前面(由于L都是合法的所以不需要存L)
这时候只要不断删除顶部非法的R,就可以得到最小的R-L+1
,然后我这边用map存了答案,遍历一遍原序,访问map拿答案
OA:为什么不是先排序R再排序R-L+1
?
因为假设[1,7] [2,7] [6,8]
,对于查询7来说选择[4,8]
是最好的,找最小的R-L+1
才是优先,不过同样的,如果是查询8,按照我们先R-L+1
再R的顺序排序[6,8] [2,7] [1,7]
,[6,8]
直接就是最好的,会有非法的R残留,不过重点是找最小的合法的R-L+1
,优先提供最小的R-L+1
,,再去判断它合不合法
实际代码:文章来源:https://www.toymoban.com/news/detail-599061.html
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
/*
bool cmp1(const PII& L,const PII& R)//自定义排序函数
{
if(L.first==R.first) return L.second>R.second;
else return L.first>R.first;
}*/
struct cmp1//自定义排序类
{
bool operator() (const PII& L,const PII& R)
{
if(L.first==R.first) return L.second>R.second;
else return L.first>R.first;
}
};
vector<int> minInterval(vector<vector<int>>& intervals, vector<int>& queries)
{
vector<int> q=queries;//拷贝-原序
//priority_queue<PII,vector<PII>,decltype(&cmp1)>p_q(cmp1); //函数式自定义优先队列
priority_queue<PII,vector<PII>,cmp1>p_q;//类式自定义优先队列
//优先队列 小距离优先 小右端点优先
map<int,int>mtp;//非原序存储答案
sort(queries.begin(),queries.end());
sort(intervals.begin(),intervals.end());
int left=0,lg=intervals.size();
for(auto querie:queries)
{
while(left<lg && intervals[left][0]<=querie)//左端点符合 - 步骤1
{
p_q.push({intervals[left][1]-intervals[left][0]+1,intervals[left][1]});
left++;
}
while(!p_q.empty() && p_q.top().second<querie)//右端点不符合 - 步骤2
{
p_q.pop();
}
if(!p_q.empty()) mtp[querie]=p_q.top().first;
}
for(auto &iq:q)
{
if(mtp[iq]==0) mtp[iq]=-1;
iq=mtp[iq];
}
return q;
}
int main()
{
int n;cin>>n;
vector<vector<int>> intervals;
vector<int> queries;
for(int i=1;i<=n;i++)
{
int a,b;cin>>a>>b;
vector<int>temp{a,b};
intervals.push_back(temp);
}
while(cin>>n)
{
queries.push_back(n);
}
vector<int>ans=minInterval(intervals,queries);
for(auto i:ans)
{
cout<<i<<" ";
}
cout<<endl;
return 0;
}
限制:文章来源地址https://www.toymoban.com/news/detail-599061.html
1 <= intervals.length <= 105
1 <= queries.length <= 105
intervals[i].length == 2
1 <= lefti <= righti <= 107
1 <= queries[j] <= 107
到了这里,关于2023-07-18力扣每日一题-有点难的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!