文章目录
- 日常刷题记录
- 合并果子
- 题目解析
- 算法思路
- 代码实现
- 中位数
- 题目解析
- 算法思路
- 代码实现
- C++学习笔记
- 队列queue
- 双端队列 deque
- 优先队列 priority_queue
- 定义
- 常见操作
- upper_bound
日常刷题记录
合并果子
题目解析
有一堆果子,每次可以将两小堆合并,耗费的体力为合并得到的这一堆的重量,给你每个小堆果子的重量,把这些果子合并成一堆后消耗的最小体力是多少
算法思路
由题意得知只要每次将重量最小的两堆果子合并就行了,你可以每合并一次就调用一次排序,但是STL提供了优先队列的数据结构,可以很好的完成这题,每次把前两个出队然后合并成一个再入队,直到队列里就剩一个元素。优先队列默认是降序的,所以定义的时候要注意加上greater<int>
代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
priority_queue<int, vector<int>, greater<int> > q;
int n;cin >> n;
for(int i=1;i<=n;i++){
int x;cin >> x;
q.push(x);
}
int ans=0;
while(q.size()>1){
int tem=q.top();
q.pop();
tem+=q.top();
q.pop();
q.push(tem);
ans+=tem;
}
cout << ans << endl;
return 0;
}
中位数
题目解析
要求把序列里前奇数项的中位数全都输出,例如前1项、前3项、前5项…前 N + 1 2 \frac{N+1}{2} 2N+1项
算法思路
这题用vector动态数组就可以实现了,一开始想用优先队列,但是由于优先队列只能访问首元素,所以不合适。向数组中依次插入元素,当元素的个数为奇数个的时候,取中间的元素(第(i-1)/2
个元素)就可以了。重点在于怎么样插入,想象在打扑克牌时摸牌后插入的操作,只需要找到序列里第一个比当前数大的数,然后在其前面插入。STL正好提供了这样一个函数:upper_bound(序列首,序列尾,查找的数)
具体看以下代码。upper_bound
代码实现
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;cin >> n;
vector<int>a;
for(int i = 1; i <= n ; i++)
{
int x;cin >> x;
a.insert(upper_bound(a.begin(),a.end(),x),x);
if(i%2 == 1)
{
cout<<a[(i-1)/2]<<endl;
}
}
return 0;
}
python也有类似的办法但是最后一个测试点超时了,仅作为学习了解
import bisect
n=int(input())
nums=list(map(int,input().split()))
vec=[]
for i in range(1,n+1):
bisect.insort(vec,nums[i-1])#insort()函数将元素插入到vec中,并保持vec的有序性
#也可以这么写
# x=nums[i-1]
# pos = bisect.bisect_right(vec, x)
# vec.insert(pos, x)
if(i%2==1):
print(vec[(i-1)//2])
C++学习笔记
队列queue
-
创建队列:
queue<int> q1; // 使用默认构造函数创建一个空队列 queue<int> q2({1, 2, 3}); // 使用初始化列表创建队列(需要自定义构造)
-
添加元素:
push()
:将一个元素添加到队列的末尾。q.push(10); // 将10添加到队列末尾
-
移除元素:
pop()
:从队列的前端移除一个元素。q.pop(); // 移除队列前端的元素
-
访问元素:
front()
:获取队列前端的元素,但不移除它。int frontElement = q.front(); // 获取队列前端的元素
back()
:获取队列末尾的元素,但不移除它。int backElement = q.back(); // 获取队列末尾的元素
-
检查队列状态:
empty()
:检查队列是否为空。if (q.empty()) { std::cout << "队列为空" << std::endl; }
size()
:获取队列中元素的数量。size_t numElements = q.size(); // 获取队列中的元素数量
-
清空队列:
clear()
:虽然std::queue
没有直接提供clear()
函数,但可以通过循环pop()
所有元素来实现清空操作。
双端队列 deque
Q.push_back()
在队尾插入一个元素
Q.push_front()
在队首插入一个元素
Q.push_back()
在队尾移除一个元素
Q.push_front()
在队首移除一个元素
优先队列 priority_queue
为什么要用优先队列?
- 给你n个数,对于所有元素来说,找到他前面(包括他)最大的元素
定义
priority_queue
是一个模板类,基本定义如下:
#include <queue>
#include <vector>
std::priority_queue<T, Container, Compare>
- T:队列中存储的元素类型。
- Container:底层容器,默认是
std::vector<T>
。 - Compare:比较器,用于决定元素的优先级,默认是
std::less<T>
(即最大堆)。
常见操作
-
创建优先队列:
priority_queue<int> pq1; // 默认最大堆,降序 priority_queue<int, vector<int>, greater<int>> pq2; // 最小堆,升序
-
添加元素:
- 使用
push()
方法将元素添加到优先队列中。pq.push(10); // 添加元素 10
- 使用
-
移除元素:
- 使用
pop()
会移除堆顶元素,但不会返回它。pq.pop(); // 移除堆顶元素
- 使用
-
访问元素:
使用top()
访问堆顶元素(即优先级最高的元素),但不移除它。int topElement = pq.top(); // 获取堆顶元素
-
检查队列状态:
- 使用
empty()
方法检查优先队列是否为空。if (pq.empty()) { std::cout << "优先队列为空" << std::endl; }
- 使用
size()
方法获取优先队列中的元素数量。size_t numElements = pq.size(); // 获取元素数量
- 使用
upper_bound
upper_bound
函数返回一个迭代器,指向一个在有序范围内第一个大于给定值 value
的元素。简单来说,它找的是第一个比 value
大的元素的位置。如果所有元素都小于或等于 value
,则返回 last
。upper_bound
通常用于在排序好的容器中查找某个值的插入位置,以保持容器的有序性。lower_bound
同理
#include <bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec{1,4,7,8,12};
int x=11;
vec.insert(upper_bound(vec.begin(),vec.end(),x),x);//在第一个比x大的位置插入x
for(auto i:vec) cout<<i<<" ";
}