priority_queue
优先队列priority_queue
头文件 #include
priority_queue < int >默认构建的是一个大根堆,所以每次从头取数据得到的是一个从大到小的队列排序.
priority_queue< int> 实际上等价于 priority_queue<int, vector, less< int>>。
top是最大的值
小根堆: priority_queue<int, vector< int>, greater< int>> q; top是最小的值
实现自己的最大堆
class mypriority_queue
{
private:
vector<int> keep;
public:
// mypriority_queue(/* args */);
// ~mypriority_queue();
void Push(int value){
keep.push_back(value);
int keepSize = keep.size()-1;
int parent = (keepSize-1)/2;
while(parent>=0 && keep[keepSize] > keep[parent]){
swap(keep[keepSize], keep[parent]);
keepSize = parent;
parent = (keepSize-1)/2;
}
return;
}
void Pop(){
int tmp = keep.back();
swap(tmp, keep[0]);
keep.pop_back();
int top = 0;
int son = top * 2 + 1; // right孩子
while(son < keep.size()){
if(son +1 < keep.size() && keep[son+1] > keep[son]){
if(keep[top] < keep[son+1]){
swap(keep[top], keep[son+1]);
top = son + 1;
son = top*2 + 1;
}else{
break;
}
}else{
if(keep[top] < keep[son]){
swap(keep[top], keep[son]);
top = son;
son = top*2 + 1;
}else{
break;
}
}
}
return;
}
int Top() const{
return keep[0];
}
int Empty() const{
return keep.empty();
}
friend ostream &operator<<(ostream &os, const mypriority_queue &mypq){
for(const auto aa : mypq.keep){
cout<<aa<<" ";
}
cout<<endl;
return os;
}
};
用法演示
// 基础用法
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector< int>, greater< int>> aa;
for(int i = 0; i< nums.size(); i++)
{
if(aa.size() < k)
{
aa.push(nums[i]);
}else if(nums[i] > aa.top()){
aa.pop();
aa.push(nums[i]);
}
}
return aa.top();
}
};
// 自定义用法
#include<iostream>
#include <queue>
using namespace std;
int main()
{
//对于基础类型 默认是大顶堆
priority_queue<int> a;
//等同于 priority_queue<int, vector<int>, less<int> > a;
// 这里一定要有空格,不然成了右移运算符↓↓
priority_queue<int, vector<int>, greater<int> > c; //这样就是小顶堆
priority_queue<string> b;
for (int i = 0; i < 5; i++)
{
a.push(i);
c.push(i);
}
while (!a.empty())
{
cout << a.top() << ' ';
a.pop();
}
cout << endl;
while (!c.empty())
{
cout << c.top() << ' ';
c.pop();
}
cout << endl;
b.push("abc");
b.push("abcd");
b.push("cbd");
while (!b.empty())
{
cout << b.top() << ' ';
b.pop();
}
cout << endl;
return 0;
}
#include <iostream>
#include <queue>
using namespace std;
//方法1
struct tmp1 //运算符重载<
{
int x;
tmp1(int a) {x = a;}
bool operator<(const tmp1& a) const
{
return x < a.x; //大顶堆
}
};
//方法2
struct tmp2 //重写仿函数
{
bool operator() (tmp1 a, tmp1 b)
{
return a.x < b.x; //大顶堆
}
};
int main()
{
tmp1 a(1);
tmp1 b(2);
tmp1 c(3);
priority_queue<tmp1> d;
d.push(b);
d.push(c);
d.push(a);
while (!d.empty())
{
cout << d.top().x << '\n';
d.pop();
}
cout << endl;
priority_queue<tmp1, vector<tmp1>, tmp2> f;
f.push(b);
f.push(c);
f.push(a);
while (!f.empty())
{
cout << f.top().x << '\n';
f.pop();
}
}
multiset
MultiSet和Set的区别:
1) MultiSet
可以插入完全相同的两条记录
会提高数据插入的速度
2) Set
不可以插入完全相同的两条记录
保证记录的唯一性
由于需要查重处理,会降低数据插入的速度
可以作为一种去重的方法
用法演示
给你 n 个任务和 m 个工人。每个任务需要一定的力量值才能完成,需要的力量值保存在下标从 0 开始的整数数组 tasks 中,第 i 个任务需要 tasks[i] 的力量才能完成。每个工人的力量值保存在下标从 0 开始的整数数组 workers 中,第 j 个工人的力量值为 workers[j] 。每个工人只能完成 一个 任务,且力量值需要 大于等于 该任务的力量要求值(即 workers[j] >= tasks[i] )。
除此以外,你还有 pills 个神奇药丸,可以给 一个工人的力量值 增加 strength 。你可以决定给哪些工人使用药丸,但每个工人 最多 只能使用 一片 药丸。
给你下标从 0 开始的整数数组tasks 和 workers 以及两个整数 pills 和 strength ,请你返回 最多 有多少个任务可以被完成。
C++ lower_bound()函数
lower_bound() 函数用于在指定区域内查找不小于目标值的第一个元素。也就是说,使用该函数在指定范围内查找某个目标值时,最终查找到的不一定是和目标值相等的元素,还可能是比目标值大的元素。
class Solution {
public:
int maxTaskAssign(vector<int>& tasks, vector<int>& workers, int pills, int strength) {
int n = tasks.size(), m = workers.size();
sort(tasks.begin(), tasks.end());
sort(workers.begin(), workers.end());
auto check = [&](int mid) -> bool {
int p = pills;
// 工人的有序集合
multiset<int> ws;
for (int i = m - mid; i < m; ++i) {
ws.insert(workers[i]);
}
// 从大到小枚举每一个任务
for (int i = mid - 1; i >= 0; --i) {
// 如果有序集合中最大的元素大于等于 tasks[i]
if (auto it = prev(ws.end()); *it >= tasks[i]) {
ws.erase(it);
}
else {
if (!p) {
return false;
}
auto rep = ws.lower_bound(tasks[i] - strength);
if (rep == ws.end()) {
return false;
}
--p;
ws.erase(rep);
}
}
return true;
};
int left = 1, right = min(m, n), ans = 0;
while (left <= right) {
int mid = (left + right) / 2;
if (check(mid)) {
ans = mid;
left = mid + 1;
}
else {
right = mid - 1;
}
}
return ans;
}
};
unordered_set
头文件 #include<unordered_set>
unordered_set可以把它想象成一个集合,它提供了几个函数让我们可以增删查:
unordered_set::insert
unordered_set::find
unordered_set::erase
用法演示
class Solution {
public:
int countVowelSubstrings(string word) {
int n = word.size();
int res = 0;
unordered_set<char> vowelset = {'a', 'e', 'i', 'o', 'u'}; // 所有元音对应的哈希集合
for (int i = 0; i < n; ++i){
// 枚举左端点
unordered_set<char> charset; // 子串对应的哈希集合
for (int j = i; j < n; ++j){
// 按顺序枚举右端点并更新子串哈希集合及比较
charset.insert(word[j]);
if (charset == vowelset){
++res;
}
}
}
return res;
}
};
map 和 unordered_map
需要引入的头文件不同
map: #include < map >
map 由红黑树实现的已排序
unordered_map: #include < unordered_map >
无重复key,未排序的哈希表
用法演示
给你一个字符串 s ,其中包含字母顺序打乱的用英文单词表示的若干数字(0-9)。按 升序 返回原始的数字。
class Solution {
public:
string originalDigits(string s) {
unordered_map<char, int> c;
for (char ch: s) {
++c[ch];
}
vector<int> cnt(10);
cnt[0] = c['z'];
cnt[2] = c['w'];
cnt[4] = c['u'];
cnt[6] = c['x'];
cnt[8] = c['g'];
cnt[3] = c['h'] - cnt[8];
cnt[5] = c['f'] - cnt[4];
cnt[7] = c['s'] - cnt[6];
cnt[1] = c['o'] - cnt[0] - cnt[2] - cnt[4];
cnt[9] = c['i'] - cnt[5] - cnt[6] - cnt[8];
string ans;
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < cnt[i]; ++j) {
ans += char(i + '0');
}
}
return ans;
}
};