Leetcode每日一题(困难):1851. 包含每个查询的最小区间(2023.7.18 C++)

目录

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

实现代码与解析:

排序 + 哈希

class Solution {
public:
    vector minInterval(vector>& itv, vector& qr) {
        vector res(qr.size(), -1);
        set> st;
        for (int i = 0; i < qr.size(); i++) st.insert({qr[i], i}); // <所求数字,编号>
        // 区间从小到大排 lambda表达式
        sort(itv.begin(), itv.end(), [&](const auto &a, const auto &b){
            return a[1] - a[0] < b[1] - b[0];
        });
        for (int i = 0; i < itv.size(); i++)
        {
            auto it = st.lower_bound({itv[i][0], - 1}); //第一个大于等于左边界
            //找出左边界和右边界之间包含的查询
            for (it; it != st.end() && (it->first < itv[i][1] || it->first == itv[i][1]);)
            {
                res[it->second] = itv[i][1] - itv[i][0] + 1; //查询编号,得到结果
                st.erase(it++);// 删除已经得到结果的que.防止下次覆盖,改变结果
            }
        }
        return res;
    }
};

原理思路:

        首先,按照区间大小对itv进行排序,然后利用set>对qr进行排序,同时记录其编号,并且创建一个res数组,存放结果,初始化为 -1 。

        遍历itv,在set中找出第一个大于等于itv[i][0]的位置(左端点),然后开始遍历set中储存的询问,找出小于等于 itv[i][0](右端点)的询问,根据记录的编号位置,给对应位置的res赋值位区间长度,同时删除(set.erase)已经得到结果的询问,最终得到所有结果。

        注意一定不要把遍历set时的it++放入for()中,而是放入erase中。

        lower_bound(x) 是用来寻找第一个大于等于x的位置。

        upper_bound(x) 是用来寻找第一个大于x的位置。

不得不说在写仿函数的时候 lambda 写起来确实方便很多,学到了。

        一开始我写的丑陋代码,大家可以不用看,我自己记录一下,就过了4分之3,把qr排序来优化一下应该也可以过。

class Solution {
public:
    class mycomparison {
    public:
        bool operator()(const pair& a, const pair& b) 
        {
            return a.first > b.first;
        }
    };
    vector minInterval(vector>& intervals, vector& queries) {

        vector qr(10000010, -1); // 用于预处理
        vector res; // 放结果
        priority_queue, vector>, mycomparison> que; // pair<区间长度,编号>小堆,区间长度排序
        for (int i = 0; i < intervals.size(); i++)
        {
            que.push({intervals[i][1] - intervals[i][0] + 1, i}); // pair<长度,编号>
        }
        while(que.size())
        {
            auto t = que.top();
            int len = t.first; // 区间长度
            int idx = t.second; // 此区间编号
            int r = intervals[idx][1]; // 右端点
            int l = intervals[idx][0]; // 左端点

            for (int i = l; i <= r; i++)
            {
                if (qr[i] == -1)
                {
                    qr[i] = len;
                }
                
            }
            que.pop();
        }
        for (int i = 0; i < queries.size(); i++)
        {
            res.push_back(qr[queries[i]]);
        }

        return res;
    }
};

你可能感兴趣的:(Leetcode,leetcode,c++,算法)