STL练习

题目来源 : 牛客网

栈和排序 (nowcoder.com)

请添加图片描述

题目分析

  1. 对于每一个入栈的元素 有两种操作
    1. 入栈
    2. 直接输出(入栈再出栈)
  2. 如何选择这两种操作呢?
    • 考虑题目要求: 要求输出的序列从大到小(如无法排序,则字典序越大越好)
    • 数字最大的最先出栈肯定是最优的
    • 数字最大 && 且能较先出栈的(当前栈顶元素 && 未入栈元素里)

代码

#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)请添加图片描述

题目分析

  1. 题目要求 : 合并相邻的相同泡泡
    • 两个小泡泡 = 一个大泡泡
    • 两个大泡泡 = 空
  2. 如何实现呢?
    1. 可以用栈这个数据结构。
      • 为什么呢? 因为我们想处理的是相邻的泡泡, 而栈是一个只维护栈顶的一个数据结构,很符合我们的要求
    2. 实现思想
      • 对当前泡泡和栈顶泡泡进行匹配判断(栈非空时), 栈空时,直接将当前泡泡入栈

代码

#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)

![请添加图片描述](https://img-blog.csdnimg.cn/direct/24634c9fede748a4820e20f3b5f24ede.png请添加图片描述

题目分析

  1. 对于每一个进程,都有相应的优先级 —> 不是由单一元素决定的优先级
    1. 用什么数据结构维护这个待运行的进程队列呢?
      • 想到一个数据结构 : 优先队列 (特点 :我们一般访问优先队列的队头元素 —> 堆中优先级最高的元素)
      • 我们可以定义一个结构体 node (有进程号, 到达时间, 执行时间, 优先级四个成员)作为优先队列的容器, 那么我们自定义结构体做容器, 优先队列默认是用 < 比较的, 所以我们需要重载一下 < 运算符
    2. 有了这个队列之后呢?
      • 我们就可以按照我们定义的规则操作进程了(进程调度)
      • 所以我们的目的是,将能执行完的进程执行完, 执行不完的进程都入队,然后一个一个出队即可。

代码

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值