一些可用于排序的函数(2542. 最大子序列的分数)
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)
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函数用于生成连续递增的序列
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<>(最小堆)
#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 的比较逻辑与常规排序相反,默认最大堆思想,大的放后面。
#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"); // 长度5pq.push("banana"); // 长度6pq.push("pear"); // 长度4while (!pq.empty()) {cout << pq.top() << " "; // 输出:pear apple bananapq.pop();}return 0;
}
方法 2:使用 lambda 表达式(C++11 及以上)
定义一个存储pair的优先队列,按pair的第二个元素升序排序
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表示第一个参数的优先级低于第二个参数(即第二个参数应该排在前面)。
