文章目录
一、2099. 找到和最大的长度为 K 的子序列
1.原题链接
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.原题链接
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.原题链接
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.原题链接
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;
}
};
总结
第二十一天,今天的题目还是比较难的。