五月集训(第二十一日)堆

一、2099. 找到和最大的长度为 K 的子序列

1.原题链接

2099. 找到和最大的长度为 K 的子序列

2.题目描述

        给你一个整数数组 nums 和一个整数 k 。你需要找到 nums 中长度为 k 的 子序列 ,且这个子序列的 和最大 。请你返回 任意 一个长度为 k 的整数子序列。子序列 定义为从一个数组里删除一些元素后,不改变剩下元素的顺序得到的数组。

3.解题思路

        堆

4.源码

class Solution {
public:
    vector<int> maxSubsequence(vector<int>& nums, int k) {
        int n = nums.size();
        priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> res;
        for(int i = 0; i < n;++i){
            if(res.size() < k)res.push({nums[i],i});
            else if(res.size() == k && res.top().first < nums[i]){
                res.pop();
                res.push({nums[i],i});
            }
        }
        vector<int> ans(k),temp(k);
        int idx = 0;
        while(!res.empty()){
            temp[idx++] = res.top().second;
            res.pop();
        }
        sort(temp.begin(),temp.end());
        for(int i = 0; i < k;++i){
            ans[i] = nums[temp[i]];
        }
        return ans;
    }
};

二、1792. 最大平均通过率

1.原题链接

1792. 最大平均通过率

2.题目描述

        一所学校里有一些班级,每个班级里有一些学生,现在每个班都会进行一场期末考试。给你一个二维数组 classes ,其中 classes[i] = [passi, totali] ,表示你提前知道了第 i 个班级总共有 totali 个学生,其中只有 passi 个学生可以通过考试。给你一个整数 extraStudents ,表示额外有 extraStudents 个聪明的学生,他们 一定 能通过任何班级的期末考。你需要给这 extraStudents 个学生每人都安排一个班级,使得 所有 班级的 平均 通过率 最大 。一个班级的 通过率 等于这个班级通过考试的学生人数除以这个班级的总人数。平均通过率 是所有班级的通过率之和除以班级数目。请你返回在安排这 extraStudents 个学生去对应班级后的 最大 平均通过率。与标准答案误差范围在 10-5 以内的结果都会视为正确结果。

3.解题思路

        贪心+大顶堆

4.源码

class Solution {
public:
    double maxAverageRatio(vector<vector<int>>& classes, int extraStudents) {
        auto cmp = [](const pair<int, int> &p, const pair<int, int> &q) {
            unsigned long x1 = p.first, y1 = p.second;
            unsigned long x2 = q.first, y2 = q.second;
            return (x1 * (y1 + 1) - y1 * (x1 + 1)) * (x2 + 1) * x2 < (x2 * (y2 + 1) - y2 * (x2 + 1)) * (x1 + 1) * x1;
        };
        priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> heap(cmp);
        for (const auto &v : classes) {
            heap.emplace(v[1], v[0]);
        }
        for (int i = 0; i < extraStudents; ++i) {
            auto [x, y] = heap.top();
            heap.pop();
            heap.emplace(x + 1, y + 1);
        }
        double ret = 0.0;
        while (!heap.empty()) {
            auto [x, y] = heap.top();
            heap.pop();
            ret += (double)y / x;
        }
        return ret / classes.size();
    }
};

三、1499. 满足不等式的最大值

1.原题链接

1499. 满足不等式的最大值

2.题目描述

        给你一个数组 points 和一个整数 k 。数组中每个元素都表示二维平面上的点的坐标,并按照横坐标 x 的值从小到大排序。也就是说 points[i] = [xi, yi] ,并且在 1 <= i < j <= points.length 的前提下, xi < xj 总成立。请你找出 yi + yj + |xi - xj| 的 最大值,其中 |xi - xj| <= k 且 1 <= i < j <= points.length。题目测试数据保证至少存在一对能够满足 |xi - xj| <= k 的点。

3.解题思路

        贪心+队列

4.源码

class Solution {
public:
    int findMaxValueOfEquation(vector<vector<int>>& points, int k) {
        int n = points.size();
        int res = INT_MIN;
        deque<pair<int, int>> q;

        for (int i = 0; i < n; ++i)
        {
            // 判断队列first即x是否满足k的限制,不满足则弹出队头
            while (!q.empty() && points[i][0] - q.front().first > k)
            {
                q.pop_front();
            }
            // 尝试更新最大值
            if (!q.empty())
            {
                res = max(res, points[i][1] + points[i][0] + q.front().second);
            }
            // 维持队列second的单调递减,避免重复计算
            int curr = points[i][1] - points[i][0];
            while (!q.empty() && curr > q.back().second)
            {
                q.pop_back();
            }

            q.push_back({points[i][0], points[i][1]-points[i][0]});
        }

        return res;
    }
};

四、2163. 删除元素后和的最小差值

1.原题链接

2163. 删除元素后和的最小差值

2.题目描述

        给你一个下标从 0 开始的整数数组 nums ,它包含 3 * n 个元素。你可以从 nums 中删除 恰好 n 个元素,剩下的 2 * n 个元素将会被分成两个 相同大小 的部分前面 n 个元素属于第一部分,它们的和记为 sumfirst 。后面 n 个元素属于第二部分,它们的和记为 sumsecond 。两部分和的 差值 记为 sumfirst - sumsecond 。比方说,sumfirst = 3 且 sumsecond = 2 ,它们的差值为 1 。再比方,sumfirst = 2 且 sumsecond = 3 ,它们的差值为 -1 。请你返回删除 n 个元素之后,剩下两部分和的 差值的最小值 是多少。

3.解题思路

        堆(优先队列)

4.源码

class Solution {
public:
    long long minimumDifference(vector<int>& nums) {
        int n3 = nums.size(), n = n3 / 3;
        
        vector<long long> part1(n + 1);
        long long sum = 0;
        // 大根堆
        priority_queue<int> ql;
        for (int i = 0; i < n; ++i) {
            sum += nums[i];
            ql.push(nums[i]);
        }
        part1[0] = sum;
        for (int i = n; i < n * 2; ++i) {
            sum += nums[i];
            ql.push(nums[i]);
            sum -= ql.top();
            ql.pop();
            part1[i - (n - 1)] = sum;
        }
        
        long long part2 = 0;
        // 小根堆
        priority_queue<int, vector<int>, greater<int>> qr;
        for (int i = n * 3 - 1; i >= n * 2; --i) {
            part2 += nums[i];
            qr.push(nums[i]);
        }
        long long ans = part1[n] - part2;
        for (int i = n * 2 - 1; i >= n; --i) {
            part2 += nums[i];
            qr.push(nums[i]);
            part2 -= qr.top();
            qr.pop();
            ans = min(ans, part1[i - n] - part2);
        }
        return ans;
    }
};

总结

        第二十一天,今天的题目还是比较难的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枏念

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值