文章目录
- [栈和排序 (nowcoder.com)](https://ac.nowcoder.com/acm/problem/14893)
- 题目分析
- 代码
- [吐泡泡 (nowcoder.com)](https://ac.nowcoder.com/acm/problem/15029)
- 题目分析
- 代码
- [[HNOI2003]操作系统 (nowcoder.com)](https://ac.nowcoder.com/acm/problem/20030)
- 题目分析
- 代码
题目来源 : 牛客网
栈和排序 (nowcoder.com)
题目分析
- 对于每一个入栈的元素 有两种操作
- 入栈
- 直接输出(入栈再出栈)
- 如何选择这两种操作呢?
- 考虑题目要求: 要求输出的序列从大到小(如无法排序,则字典序越大越好)
- 数字最大的最先出栈肯定是最优的
- 数字最大 && 且能较先出栈的(当前栈顶元素 && 未入栈元素里)
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
stack<int> s;
int n, a[maxn];
int maxh[maxn]; // maxh[i] 表示 a[i, n]的最大值, 表示未入栈的数字的最大值
int main()
{
cin >> n;
// 记录入栈元素
for(int i = 1; i <= n; ++i){
cin >> a[i];
}
// 计算 maxn 数组
maxh[n] = a[n];
for(int i = n - 1; i >= 1; i--) // maxh[i]表示[i, n] 范围内的最大值
maxh[i] = max(a[i], maxh[i + 1]);
// 模拟入栈, 按要求入栈 && 出栈 ---> 获得目标序列
for(int i = 1; i <= n; ++i)
{
if(a[i] == maxh[i]){ // 将未入栈中的最大值出栈
cout << a[i] << " "; // 直接出栈
}
else s.push(a[i]);
// cout << s.size() << " "<< s.top() << " "<< s.size() && s.top();
// cout << '\n';
while(s.size() && s.top() > maxh[i + 1]) // 保证栈顶元素小于等于未入栈元素的最大值
{
cout << s.top() << " ";
s.pop();
}
}
cout << '\n';
return 0;
}
吐泡泡 (nowcoder.com)
题目分析
- 题目要求 : 合并相邻的相同泡泡
- 两个小泡泡 = 一个大泡泡
- 两个大泡泡 = 空
- 如何实现呢?
- 可以用栈这个数据结构。
- 为什么呢? 因为我们想处理的是相邻的泡泡, 而栈是一个只维护栈顶的一个数据结构,很符合我们的要求
- 实现思想
- 对当前泡泡和栈顶泡泡进行匹配判断(栈非空时), 栈空时,直接将当前泡泡入栈
- 可以用栈这个数据结构。
代码
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<char> a; // 用来存储处理泡泡的栈
stack<char> b; // 辅助栈, 用来保持原有的泡泡顺序
string s;
while (cin >> s) {
for (int i = 0; i < (int)s.length(); ++i) {
if (!a.empty()) {
if (a.top() == 'o' && a.top() == s[i]) { // 小泡泡且与栈顶元素匹配
a.pop(); // 合成大泡泡
if (!a.empty() && a.top() == 'O') // 判断栈中是否有与此大泡泡匹配的
a.pop();
else
a.push('O');
} else if (a.top() == 'O' && a.top() == s[i])
a.pop();
else
a.push(s[i]);
} else
a.push(s[i]);
}
while (!a.empty()) { // 将栈 a 放入辅助栈 b --> 还原原始顺序
b.push(a.top());
a.pop();
}
while (!b.empty()) { // 输出处理后的泡泡
cout << b.top();
b.pop();
}
cout << '\n';
}
return 0;
}
[HNOI2003]操作系统 (nowcoder.com)

- 我们可以定义一个结构体 node (有进程号, 到达时间, 执行时间, 优先级四个成员)作为优先队列的容器, 那么我们自定义结构体做容器, 优先队列默认是用 < 比较的, 所以我们需要重载一下 < 运算符
- 有了这个队列之后呢?
- 我们就可以按照我们定义的规则操作进程了(进程调度)
- 所以我们的目的是,将能执行完的进程执行完, 执行不完的进程都入队,然后一个一个出队即可。
- 用什么数据结构维护这个待运行的进程队列呢?
代码
#include<iostream>
#include<queue>
using namespace std;
struct node{
int a, b, c, d;
bool operator <(const node & x) const{ // 优先队列重载小于号
if(d == x.d)return b > x.b; // 如果进程优先级相同, 则到达时间早的优先级更高
else return d < x.d; // d 越大优先级越高
}
};
node x; // x 为刚到达的进程, execque 队列为待执行队列
priority_queue<node>execque; // 待执行队列, 默认大顶堆, 堆顶元素的优先级最高,最先出队
int t; // 当前时间, 默认为 0
int main(){
while(cin >> x.a >> x.b >> x.c >> x.d){ // 当前节点到达
// 能直接执行的就先直接执行
while(!execque.empty() && t + execque.top().c <= x.b){ // 当队列不为空且队首元素可以执行时
node curnode = execque.top();
t += curnode.c;
cout << curnode.a << " " << t << '\n';
execque.pop();
}
// 不能执行的就先放到待执行队列中
if(!execque.empty()){ // 当队列不为空且执行队列的队首元素(优先级最高元素)的优先级低于当前到达 x 的优先级时
node curnode = execque.top();
curnode.c = curnode.c - (x.b - t); // 更新队首元素的执行时间, 再将其Push回待执行队列
execque.pop();
execque.push(curnode);
}
execque.push(x); // 处理完待执行队列, 将当前队列放到待执行队列中
t = x.b; // 更新当前时间
}
// 处理待执行队列中的元素
while(!execque.empty()){
node curnode = execque.top();
t += curnode.c;
cout << curnode.a << " " << t << '\n';
execque.pop();
}
return 0;
}