蓝桥杯备赛练习题01

一、栈

1.单调栈

P2947 [USACO09MAR] Look Up S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

典型的单调栈题型。

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <unordered_map>
#include <vector>
#include <queue>
#include <stack>

stack<int> s;//存入的是下标
vector<int> nums;


int main(){
    int n;
    cin>>n;
    vector<int> result(n,0);
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        nums.push_back(x);
        while(!s.empty()&&x>nums[s.top()]){
            result[s.top()]=i+1;
            s.pop();
        }
        s.push(i);
    }
    for(int i=0;i<n;i++){
        cout<<result[i]<<endl;
    }
    return 0;
}

2.栈

1363 -- Rails (poj.org)(栈的出栈顺序问题)

题目大意: A站有编号为1到N,N最大1000,的车厢,车厢进入中转station了就不能回到A,只能停在station内或者进入B站,问能不能按照给定的顺序排成那样的车厢号。

解题: 每次一个新车厢进入station前,检查栈内栈顶元素是否与B站没有匹配的车厢头是否相等(如果有,则弹栈,重复此步骤),没有匹配的直接入栈。最后栈为空则可以排成给定次序。

举个例子:(2,1,3,5,4)能不能排成这样。

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <vector>
#include <queue>
#include <stack>
#include<string>
int N;
string StackOrder(vector<int> seq){
    stack<int> s;
    int cnt=0;
    for(int i=1;i<=N;i++){
        while(!s.empty()&&s.top()==seq[cnt]){
            s.pop();
            cnt++;
        }
        s.push(i);
    }
    while(!s.empty()&&s.top()==seq[cnt]){
        s.pop();
        cnt++;
    }
    if(s.empty()){
        return "Yes";
    }else{
        return "No";
    }

}

int main(){
    while (true) {

        cin >> N; // 读取 N
        if (N == 0) break; // 如果 N 是 0,结束输入

        while (true) {
            vector<int> Seq(N);
            cin >> Seq[0]; // 读取排列的第一个数
            if (Seq[0] == 0) break; // 如果第一个数是 0,结束当前块

            // 读取排列的剩余部分
            for (int i =1; i < N; i++) {
                cin >> Seq[i];
            }
            cout<<StackOrder(Seq)<<endl;
        }
        cout<<endl;
    }
    return 0;
}

2.1686 -- Lazy Math Instructor (poj.org)

我的主要想法就是中缀表达式转换为后缀表达式(逆波兰)

中缀表达式 : a + b

前缀表达式 : + a b

后缀表达式 : a b +

  1. 转换过程:(中缀转后缀)

    • 遇到操作数(如 a,b,c,2a,b,c,2),直接添加到输出列表。

    • 遇到运算符,与栈顶的运算符比较优先级:

      • 如果栈顶运算符优先级较高或相等,则弹出栈顶运算符并添加到输出列表,重复此过程直到栈顶运算符优先级较低或栈为空。

      • 将当前运算符压入栈中。

    • 遇到左括号 (,压入栈中。

    • 遇到右括号 ),弹出栈中的运算符并添加到输出列表,直到遇到左括号 (,左括号弹出但不输出。

    • 表达式扫描完毕后,将栈中剩余的运算符依次弹出并添加到输出列表。

当转换为逆波兰表达式后就可以求值(类似题目):150. 逆波兰表达式求值 - 力扣(LeetCode)

cpp 复制代码
class Solution {
public:
    bool isNumber(string& token) {
        return !(token == "+" || token == "-" || token == "*" || token == "/");
    }

    int evalRPN(vector<string>& tokens) {
        stack<int> nums;
        for(int i=0;i<tokens.size();i++){
           if(isNumber(tokens[i])) nums.push(atoi(tokens[i].c_str()));
           else{
               int num2=nums.top();nums.pop();//注意后入的在后
               int num1=nums.top();nums.pop();
               if (tokens[i] == "+") {
                   nums.push(num1 + num2);
               } else if (tokens[i] == "-") {
                   nums.push(num1 - num2);
               } else if (tokens[i] == "*") {
                   nums.push(num1 * num2);
               } else if (tokens[i] == "/") {
                   nums.push(num1 / num2);
               }
           }
        }
      
        return  nums.top();
    }

};

还可以写的更优雅:

cpp 复制代码
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        unordered_map<string,function<int(int,int)>> map={
            {"+",[](int a,int b){return a+b;}},
            {"-",[](int a,int b){return a-b;}},
            {"*",[](int a,int b){return a*b;}},
            {"/",[](int a,int b){return a/b;}}
        } ;
        stack<int> st;
        for(string& s:tokens)
        {
            if(map.count(s))
            {
                int right=st.top();st.pop();
                int left=st.top();st.pop();
                st.push(map[s](left,right));
            }
            else
                st.push(stoi(s));
        }
        return st.top();
    }
};

对于此题:

1.转化为逆波兰表达式2.计算比较

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <vector>
#include <queue>
#include <stack>
#include<string>
map<char,int> m;
string transform_str(string str){
    string re="";
    stack<char> punc;
    for(int i=0;i<str.size();i++){
        if(isalnum(str[i])) re+=str[i];
        else{
            switch(str[i]){
                case '(': punc.push(str[i]);break;
                case ')':
                    while(punc.top()!='('){
                        re+=punc.top();
                        punc.pop();
                    }
                    punc.pop();
                    break;
                case '+':
                case '-':
                case '*':
                    while(!punc.empty()&&m[str[i]]<=m[punc.top()]){
                        re+=punc.top();
                        punc.pop();
                    }
                    punc.push(str[i]);
                    break;
            }
        }

    }
    while(!punc.empty()){
        re+=punc.top();
        punc.pop();
    }
    return re;
}
int result(string nt){
    stack<int> nums;
    for(int i=0;i<nt.length();i++){
        char c=nt[i];
        if(isalnum(c)){
            if(isdigit(c)) {
                nums.push(c-'0');
            }else{
                nums.push(c);//字母用其ASCII代替
            }
        }
        else{
            int num2=nums.top();nums.pop();
            int num1=nums.top();nums.pop();
            switch(c){
                case '+': nums.push(num1+num2);break;
                case '-': nums.push(num1-num2);break;
                case '*': nums.push(num1*num2);break;
            }
        }

    }
    return nums.top();
}
//void test(){
//    string s;
//    cin>>s;
//    string r=transform_str(s);
//    cout<<r<<endl;
//    cout<<result(r)<<endl;
//};
int main(){
    m['(']=0;m['+']=m['-']=1;m['*']=2;
    int T;
    cin>>T;
    cin.get();

    while(T--){
        string str1,str2;
        getline(cin,str1);getline(cin,str2);
        string n1=transform_str(str1); string n2=transform_str(str2);
        if(result(n1)==result(n2)) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

oj平台有些问题,还在等待。

3.2106 -- Boolean Expressions (poj.org)

F是0,V是1,运算符有& ! | ( )这五个,优先级为! > & > |当然有括号肯定先算括号里的,中间会有若干空格。

我的思路与上题一模一样,就是现将输入的式子去除空格,然后根据优先级去掉括号形成后缀表达式,然后直接利用栈进行计算结果。

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <vector>
#include <queue>
#include <stack>
#include<string>
map<char,int> m;
string transform_str(string str){
    string re="";
    stack<char> punc;
    for(int i=0;i<str.size();i++){
        if(isalnum(str[i])) re+=str[i];
        else{
            switch(str[i]){
                case '(': punc.push(str[i]);break;
                case ')':
                    while(punc.top()!='('){
                        re+=punc.top();
                        punc.pop();
                    }
                    punc.pop();
                    break;
                case '|':
                case '&':
                case '!':
                    while(!punc.empty()&&m[str[i]]<=m[punc.top()]){
                        re+=punc.top();
                        punc.pop();
                    }
                    punc.push(str[i]);
                    break;
            }
        }

    }
    while(!punc.empty()){
        re+=punc.top();
        punc.pop();
    }
    return re;
}
char result(string nt){
    stack<bool> nums;
    for(int i=0;i<nt.length();i++){
        char c=nt[i];
        if(c=='V'){
            nums.push(1);
        }
        else if(c=='F'){
            nums.push(0);
        }
        else{
            bool log1, log2;
            switch(c){
                case '|':
                    log1=nums.top();nums.pop();
                    log2=nums.top();nums.pop();
                    nums.push(log1|log2);
                    break;
                case '&':
                    log1=nums.top();nums.pop();
                    log2=nums.top();nums.pop();
                    nums.push(log1&log2);
                    break;
                case '!':
                    log1=nums.top();nums.pop();
                    nums.push(!log1);
                    break;
            }
        }

    }
    return nums.top()==1?'V':'F';
}
string getNoSpace(string s){
    string line="";
    for (char c : s) {
        if (!isspace(c)) { // 如果不是空格
           line+=c;
        }
    }
    return line;
}
//void test(){
//    string s;
//    getline(cin,s);
//    s=getNoSpace(s);
//    string r= transform_str(s);
//    cout<<r<<endl;
//    cout<<result(r);
//};
int main() {
    m['('] = 0;
    m['|'] = 1;
    m['&'] = 2;
    m['!'] = 3;
    string str1;
    //test();
    int cnt=1;
    while(getline(cin, str1)) {
        string str = getNoSpace(str1);
        string n1 = transform_str(str1);
        cout << "Expression " << cnt++ << ": " << result(n1) << endl;
    }
    return 0;
}

同样:

二、队列

1.基础知识

1.3210 A Stack or A Queue? - ZOJ Problem Set (pintia.cn)(基础主要是队列与栈结构(简单))

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <unordered_map>
#include <vector>
#include <queue>
#include <stack>
#include<string>
int N;

bool isStack(vector<int> in,vector<int> out){
    int i=0,j=N-1;
    for(;i<j;i++,j--){
        if(in[j]!=out[i]) return false;
    }
    return true;
}
bool isQueue(vector<int> in,vector<int> out){
    for(int i=0;i<N;i++){
        if(in[i]!=out[i]) return false;
    }
    return true;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        cin>>N;
        int x;
        vector<int> in;
        vector<int> out;
        for(int i=0;i<N;i++){
            cin>>x;
            in.push_back(x);
        }
        for(int i=0;i<N;i++){
            cin>>x;
            out.push_back(x);
        }
        bool a= isStack(in,out),b=isQueue(in,out);
        if(a&&b){
            cout<<"both"<<endl;
        }else if(b){
            cout<<"queue"<<endl;
        }else if(a){
            cout<<"stack"<<endl;
        }else{
            cout<<"neither"<<endl;
        }
    }
    return 0;
}

2.1948 Team Queue - ZOJ Problem Set (pintia.cn)(队列的小变化(模拟))

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <unordered_map>
#include <vector>
#include <queue>
#include <stack>
#include<string>
#define MAX 1001

int main(){
    int cnt=1;

    while(1){
        queue<int> teamQueue[MAX];//每个元素是队列的数组
        queue<int> team;
        map<int,int> m;
        int t;
        cin>>t;
        if(t==0) break;
        cout<<"Scenario #"<<cnt++<<endl;
        while(t--){
            int num;
            cin>>num;
            for(int i=0;i<num;i++){
                int x;
                cin>>x;
                m[x]=t;//倒序
            }
        }
        while(true){
            string op;
            cin>>op;
            if(op=="ENQUEUE"){
                int x;
                cin>>x;
                int t=m[x];
                if(teamQueue[t].empty()) team.push(t);
                teamQueue[t].push(x);
            }else if(op=="DEQUEUE"){
                if(!team.empty()){
                    int t=team.front();
                    cout<<teamQueue[t].front()<<endl;
                    teamQueue[t].pop();
                    if(teamQueue[t].empty()) team.pop();
                }
            }else{
                cout<<endl;
                break;
            }
        }

    }
    return 0;
}

3.P1540 [NOIP2010 提高组] 机器翻译 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

(模拟题,用数组其实更简单,本来我想用queue,但是无法遍历,利用deque(双端队列)就可以遍历)

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <unordered_map>
#include <vector>
#include <queue>
#include <stack>
#include<string>
deque<int> q;

bool findQ(int x){
    for(int val:q){
        if(x==val) return true;
    }
    return false;
}
int main(){
    int N,M;
    cin>>M>>N;
    int cnt=0;
    for(int i=0;i<N;i++){
        int x;
        cin>>x;
        if(q.empty()){
            q.push_back(x);
            cnt++;
            continue;
        }
        if(!findQ(x)){
            if(q.size()<M){
                q.push_back(x);
                cnt++;
            }else{
                q.pop_front();
                q.push_back(x);
                cnt++;
            }

        }
    }
    cout<<cnt;

    return 0;
}

4.3629 -- Card Stacking (poj.org)

思路:利用队列模拟过程。

代码:

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <vector>
#include <queue>
#include <stack>
#include<string>

queue<int> q;
vector<int> result;
//void test(){

//};
int main() {
    int N,K,P;
    cin>>N>>K>>P;//K=nN,P is card,M=n,K-n=n(N-1)
    for(int i=1;i<=K;i++){
        q.push(i);
    }
    int cnt=1;
    while(!q.empty()){
        if(cnt%N==0){
           result.push_back(q.front());
        }
        q.pop();//给右边
        for(int i=0;i<P;i++){
            int c=q.front();q.pop();q.push(c);//P张
        }
        cnt++;
    }
    sort(result.begin(),result.end());
    for(int i=0;i<result.size();i++){
        cout<<result[i]<<endl;
    }
    return 0;
}
  1. 3125 -- Printer Queue (poj.org)

思路:首先我们建立一个队列,然后建立一个结构体,用一个flag标记位表示我们关注的作业,然后我们按照要求模拟队列,解决问题。

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <vector>
#include <queue>
#include <stack>
#include<string>

//void test(){

//};
struct work{
    int prior;
    int flag;
};
int maxnum(queue<work> q){
    int maxv=-1;
    queue<work> temp = q;
    while (!temp.empty()) {
        maxv = max(maxv, temp.front().prior);
        temp.pop();
    }
    return maxv;
}
int main() {
    int T;scanf("%d",&T);
    queue<work> q;
    int n,m;

    while(T--){
        cin>>n>>m;
        int maxv=-1;
        for(int i=0;i<n;i++){
            int c;cin>>c;
            if(i==m) q.push({c,1});
            else q.push({c,0});
            maxv = max(maxv, c);
        }
        int time=0;
        while(!q.empty()){
            if(q.front().prior>=maxv){
                time++;
                if(q.front().flag) break;
                //更新maxv
                q.pop();
                maxv=maxnum(q);
            }
            else{
                work c=q.front();q.pop();
                q.push(c);
            }
        }
        cout<<time<<endl;
        // 清空队列
        while (!q.empty()) {
            q.pop();
        }
    }
    return 0;
}

6.p12207.pdf (onlinejudge.org)

思路:

模拟一个队列系统,处理两种特定的队列操作。每个测试用例有一个队列,队列中有初始的一系列任务编号(从1到p),并且接下来有一系列操作。操作可以是两种类型:

  1. N(Next):打印当前队列的队首元素,并将队首元素移到队尾。这相当于处理队列中的下一个任务,完成之后将其重新排队。

  2. E x(Enter) :将元素 x 移动到队首。如果队列中已有这个元素,则首先移除它,然后将它重新插入到队首。这个操作可以视作将某个任务优先处理。

通过使用 deque(双端队列)来高效实现这两种操作,因为 deque 允许从队列两端高效地插入和删除元素。每次执行完操作后,根据需求输出队列的状态。程序通过 scanfgetchar 读取输入并执行相应的操作,最后输出每个操作后的结果。

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <unordered_map>
#include <vector>
#include <queue>
#include <stack>
#include<string>

const int C = 1000;

int main()
{
    int p, c, caseno = 0;
    while(~scanf("%d%d", &p, &c) && (p || c)) {
        deque<int> dq;
        printf("Case %d:\n", ++caseno);

        for(int i = 1; i <= p && i <= C; i++) dq.push_back(i);
        while(c--) {
            char c = getchar();
            if((c = getchar()) == 'N') {
                printf("%d\n", dq.front());
                dq.push_back(dq.front());
                dq.pop_front();
            } else if(c == 'E') {
                int x;
                scanf("%d", &x);
                for(deque<int>::iterator iter = dq.begin(); iter != dq.end(); iter++)
                    if(*iter == x) {
                        dq.erase(iter);
                        break;
                    }
                dq.push_front(x);
            }
        }

    }

    return 0;
}

uva账户邮箱一直没有验证码,没有注册。

2.滑动窗口

1.P1886 滑动窗口 /【模板】单调队列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

利用优先队列结合队列解决。

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <unordered_map>
#include <vector>
#include <queue>
#include <stack>
#include<string>
priority_queue<int,vector<int>,greater<int>> q_min;
queue<int> q;
vector<int> v;
vector<int> min_num;
vector<int> max_num;
int main() {
    int n,k;
    cin>>n>>k;

    for(int i=0;i<n;i++){
        int m;
        cin>>m;
        v.push_back(m);
    }

    for (int i=0;i<k;i++){
        q.push(v[i]);
    }
    //find the min
    for(int i=k;i<=n;i++){
        queue<int> q_temp;
        while (!q.empty()) {
            q_min.push(q.front());
            q_temp.push(q.front());
            q.pop();
        }

        min_num.push_back(q_min.top());

        while (q_min.size()!=1) {
            q_min.pop();
        }
        max_num.push_back(q_min.top());
        q_min.pop();


        //update the new,and pop the old
        while (!q_temp.empty()) {
            q.push(q_temp.front());
            q_temp.pop();
        }
        q.pop();
        q.push(v[i]);

    }

    for(auto it=min_num.begin();it!=min_num.end();it++){
        cout<<*it<<" ";
    }
    cout<<endl;
    for(auto it=max_num.begin();it!=max_num.end();it++){
        cout<<*it<<" ";
    }
    return 0;
}




int main(){

    return 0;
}

会超时

还可以利用其他办法:(单调队列)

cpp 复制代码
#include <iostream>
using namespace std;
#include <algorithm>
#include<map>
#include <unordered_map>
#include <vector>
#include <queue>
#include <stack>
#include<string>

const int N=1e6+10;
#include <deque>
deque<int> dq;
int a[N];
int n,m;

int main(){
    scanf("%d%d",&n,&m);
    //最小值
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        while(dq.size()&&a[dq.back()]>a[i])  dq.pop_back();
        dq.push_back(i);
        if(i>=m){
            if(dq.front()<=i-m&&dq.size()) dq.pop_front();//为了限制这个数必须在这个滑动窗口里面
            cout<<a[dq.front()]<<" ";
        }
    }
    cout<<endl;
    dq.erase(dq.begin(),dq.end());
    //最大值
    for(int i=1;i<=n;i++){
        while(dq.size()&&a[dq.back()]<a[i])  dq.pop_back();
        dq.push_back(i);
        if(i>=m){
            if(dq.front()<=i-m&&dq.size()) dq.pop_front();
            cout<<a[dq.front()]<<" ";
        }
    }
    return 0;
}
相关推荐
Hhyao4 小时前
2024第十五届蓝桥杯网安赛道省赛题目--cc(CyberChef)/crypto
蓝桥杯·密码学
不过四级不改名6774 小时前
蓝桥杯嵌入式uart,iic,adc_scan模版
职场和发展·蓝桥杯
清弦墨客4 小时前
【蓝桥杯】43697.机器人塔
python·蓝桥杯·程序算法
Joyner20185 小时前
python-leetcode-从中序与后序遍历序列构造二叉树
算法·leetcode·职场和发展
LNsupermali5 小时前
力扣257. 二叉树的所有路径(遍历思想解决)
算法·leetcode·职场和发展
雾月555 小时前
LeetCode LCR180文件组合
算法·leetcode·职场和发展
labmem18 小时前
Leetcode:541
算法·leetcode·职场和发展
今天也想MK代码12 小时前
写好简历的三个关键认知
面试·职场和发展
JNU freshman13 小时前
蓝桥杯思维训练营(一)
蓝桥杯