2023-07-18力扣每日一题-有点难

文章介绍了如何使用优先队列解决一个二维区间数组的查询问题。给定一组区间和查询,目标是找到存在于区间内的最小R-L+1,满足L≤M[i]≤R。通过离线查询,对区间和查询排序,使用双指针和自定义排序的优先队列,逐步排除非法区间,找到每个查询的最小区间。
摘要由CSDN通过智能技术生成

链接:

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,,再去判断它合不合法

实际代码:

#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;
}

限制:

  • 1 <= intervals.length <= 105
  • 1 <= queries.length <= 105
  • intervals[i].length == 2
  • 1 <= lefti <= righti <= 107
  • 1 <= queries[j] <= 107
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值