2542. 最大子序列的分数
题目要求两个数组(nums1、nums2)选k个数后经过运算得到的最大值
运算:nums1中k个数之和 * min(nums2中对应下标元素)
一开始准备用类似于找第k大的数的快排划分方法写,后来发现min(nums2中对应下标元素)不一定就是这个第k大的数,因为num1和部分的运算也有影响。×
后来参考别人的代码,用最小堆枚举nums2元素,将nums2元素的下标按nums2值从大到小排序,num1下标与num2下标关联起来,找前k个和最大的值。代码如下:
- ids存数组下标
- 对下标按nums2的值从大到小排序
- 初始化结果,ans = 前k大的下标的nums1之和*第k大的nums2
- 枚举:ans = max(前k+i下标的nums1最大k个之和*第k+i大的nums2,ans)
cpp
class Solution {
public:
long long maxScore(vector<int> &nums1, vector<int> &nums2, int k) {
int n = nums1.size();
vector<int> ids(n);//ids存两个数组关联的下标
//1.初始化下标
iota(ids.begin(), ids.end(), 0);
//2.对下标按nums2的值排序,不影响原数组的顺序
//当 nums2[i] 大于 nums2[j] 时,i 排在 j 前面(降序)
ranges::sort(ids, [&](int i, int j) { return nums2[i] > nums2[j]; });
//3.最小堆
priority_queue<int, vector<int>, greater<>> pq;
long long sum = 0;
for (int i = 0; i < k; i++)
{
//前k个求和
sum += nums1[ids[i]];
// pq.top()存这k个里面最小的值
pq.push(nums1[ids[i]]);
}
//初始结果
long long ans = sum * nums2[ids[k - 1]];
//枚举
for (int i = k; i < n; i++) {
int x = nums1[ids[i]];
//如果num1这个值比之前求和最小的大
if (x > pq.top())
{//把这个值放入求和中,之前求和最小值删除
sum += x - pq.top();
pq.pop();
pq.push(x);
//重新计算结果
ans = max(ans, sum * nums2[ids[i]]);
}
}
return ans;
}
};
一、 iota函数
头文件: <numeric>
iota函数用于生成连续递增的序列
cpp
template< class ForwardIt, class T >
void iota( ForwardIt first, ForwardIt last, T value );
- 从
value
开始,为**[**first, last
**)**范围内的元素依次赋上连续递增的值 - 第一个元素被赋值为
value
- 第二个元素被赋值为
value + 1
- 第三个元素被赋值为
value + 2
- 以此类推,直到填充完整个范围
特点
- 效率高:时间复杂度为 O (n),n 是范围中的元素数量
- 灵活性强:可以用于任何支持正向迭代器的容器(如 array、list 等)
- 支持多种数据类型:只要支持
++
运算符的类型都可以使用(如整数、字符等)
二、 ranges::sort
头文件:<ranges>
C++20 引入的范围库中的排序函数
与传统的 std::sort
相比,它可以直接对容器进行排序**(无需传入迭代器对)。**
三、priority_queue
(优先队列)
头文件:<queue>
priority_queue
(优先队列)是 C++ 标准库中的一个容器适配器,它提供了一种自动排序的队列功能,每次从队列中取出的元素都是当前队列中优先级最高的元素。
核心特性
- 默认行为 :默认情况下是最大堆(max-heap),即每次取出的元素是当前队列中最大的。
- 底层容器 :默认使用
vector
作为底层存储容器,也可以指定为deque
。 - 排序规则 :通过比较函数(或函数对象)控制排序,默认使用
less<Type>
(降序排序)。
基本用法
less<>
(默认,最大堆)和 greater<>
(最小堆)
cpp
#include <queue>
using namespace std;
// 定义一个存储int类型的优先队列(默认是最大堆)
priority_queue<int> pq;
// 定义最小堆(需指定比较函数)
priority_queue<int, vector<int>, greater<int>> min_pq;
操作
操作 | 功能描述 | 时间复杂度 |
---|---|---|
pq.push(value) |
插入元素到队列 | O(log n) |
pq.top() |
获取队首元素(优先级最高) | O(1) |
pq.pop() |
删除队首元素 | O(log n) |
pq.empty() |
判断队列是否为空 | O(1) |
pq.size() |
获取队列中元素的个数 | O(1) |
自定义排序规则
方法 1:使用函数对象(functor)
priority_queue
的比较逻辑与常规排序相反, 默认最大堆思想,大的放后面。
cpp
#include <queue>
#include <string>
// 自定义比较规则:按字符串长度升序排序
struct StrCompare {
bool operator()(const string& a, const string& b) {
return a.size() > b.size();
}
};
int main() {
priority_queue<string, vector<string>, StrCompare> pq;
pq.push("apple"); // 长度5
pq.push("banana"); // 长度6
pq.push("pear"); // 长度4
while (!pq.empty()) {
cout << pq.top() << " "; // 输出:pear apple banana
pq.pop();
}
return 0;
}
方法 2:使用 lambda 表达式(C++11 及以上)
定义一个存储pair的优先队列,按pair的第二个元素升序排序
cpp
auto cmp = [](const pair<int, int>& a, const pair<int, int>& b) {
return a.second > b.second; // 小的second值优先级高
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> pq(cmp);
适用场景
- 需要频繁获取最大值 / 最小值的场景(如 Top K 问题)
- 贪心算法的实现(如霍夫曼编码、活动选择问题)
- 图算法(如 Dijkstra 最短路径算法、Prim 最小生成树)
- 任务调度(按优先级处理任务)
注意事项
priority_queue
没有迭代器,无法遍历所有元素(只能通过top()
获取顶部元素,再pop()
删除)。- 插入和删除操作的时间复杂度是 O (log n),效率较高。
- 自定义排序时,比较函数的返回值含义是:
return true
表示第一个参数的优先级低于第二个参数(即第二个参数应该排在前面)。