2020-10-11

第三章 栈与队列

1:滑动窗口

描述
给定一个长度为n(n<=10^6)的数组。有一个大小为k的滑动窗口从数组的最左端移动到最右端。你可以看到窗口中的k个数字。窗口每次向右滑动一个数字的距离。
下面是一个例子:
数组是 [1 3 -1 -3 5 3 6 7], k = 3。

窗口位置 最小值 最大值
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7

你的任务是得到滑动窗口在每个位置时的最大值和最小值。

输入
输入包括两行。
第一行包括n和k,分别表示数组的长度和窗口的大小。
第二行包括n个数字。

输出
输出包括两行。
第一行包括窗口从左至右移动的每个位置的最小值。
第二行包括窗口从左至右移动的每个位置的最大值。

样例输入
8 3
1 3 -1 -3 5 3 6 7
样例输出
-1 -3 -3 -3 3 3
3 3 5 5 6 7

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int n, k, tmp;
deque<int>p;
deque<int>q;
vector<int>arr;
vector<int>MyMax;
vector<int>MyMin;
int main() {
    cin >> n >> k;
    for(int i = 0; i < n; ++i){
        scanf("%d", &tmp);
        arr.push_back(tmp);
    }
    
    for(int i = 0; i < n; ++i){
        if(!p.empty() && p.front() == i - k)//把窗口划过部分的序号删掉
            p.pop_front();
        
        while(!p.empty() && arr[p.back()] < arr[i])//删去队尾比当前元素小的,肯定用不到他们
            p.pop_back();
        p.push_back(i);//当前元素入队
        
        if (i >= k - 1)//从k-1开始记录(第一个窗口
            MyMax.push_back(arr[p.front()]);
    }
    
    for(int i = 0; i < n; ++i){
        if(!q.empty() && q.front() == i - k)
            q.pop_front();
        while(!q.empty() && arr[q.back()] > arr[i])
            q.pop_back();
        q.push_back(i);
        if (i >= k - 1)
            MyMin.push_back(arr[q.front()]);
    }
    
    for(int i = 0; i <= n - k; ++i)
        cout << MyMin[i] << ' ';
    
    cout << endl;
    
    for(int i = 0; i <= n - k; ++i)
        cout << MyMax[i] << ' ';
    
    return 0;
}

2:中缀表达式的值

总时间限制: 200ms 内存限制: 1024kB

描述
人们熟悉的四则运算表达式称为中缀表达式,例如(23+34*45/(5+6+7))。在程序设计语言中,可以利用堆栈的方法把中缀表达式转换成保值的后缀表达式(又称逆波兰表示法),并最终变为计算机可以直接执行的指令,得到表达式的值。

给定一个中缀表达式,编写程序,利用堆栈的方法,计算表达式的值。

输入
第一行为测试数据的组数N
接下来的N行,每行是一个中缀表达式。表达式中只含数字、四则运算符和圆括号,操作数都是正整数,数和运算符、括号之间没有空格。中缀表达式的字符串长度不超过600。

输出
对每一组测试数据输出一行,为表达式的值

样例输入
3
3+5*8
(3+5)8
(23+34
45/(5+6+7))

样例输出
43
64
108

提示
注意:运算过程均为整数运算(除法运算’/'即按照C++定义的int除以int的结果,测试数据不会出现除数为0的情况),输出结果也为整数(可能为负)。
中间计算结果可能为负。

#include <iostream>
#include <set>
#include <stdlib.h>
#include <string>
#include <stdio.h>
#include <vector>
#include <stack>
#include <sstream>
using namespace std;
int t = 0;
int main() {
    cin >> t;
    cin.get();
    char tmp = 0;
    int opnum = 0;
    while(t--){
        stack<char>s;
        stack<int>pos;
        char line[610] = {};
        string posExpression = "";
        stringstream ss;
        cin.getline(line, 609, '\n');
        int i = 0;
        while(line[i] && i < 610){
            if(line[i] == '('){
                s.push('(');
                ++i;
            }
            else if(line[i] >= '1' && line[i] <= '9'){
                posExpression += line[i];
                ++i;
                while(line[i] >= '0' && line[i] <= '9'){
                    posExpression += line[i];
                    ++i;
                }
                posExpression += " ";
            }
            else if(line[i] == ')'){
                while(s.top() != '('){
                    posExpression += s.top();
                    posExpression += " ";
                    s.pop();
                }
                s.pop();
                ++i;
            }
            else{
                while((!s.empty()) && (s.top() != '(') && (((s.top() == '+' || s.top() == '-' )&&(line[i] == '+' || line[i] == '-' )) || (s.top() == '*' || s.top() == '/'))){
                    posExpression += s.top();
                    posExpression += " ";
                    s.pop();
                }
                s.push(line[i++]);
            }
        }
        while(!s.empty()){
            posExpression += s.top();
            posExpression += " ";
            s.pop();
        }
        ss.clear();
        ss << posExpression;
        //cout << posExpression << endl;
        while(ss >> tmp){
            if(tmp >= '1' && tmp <= '9'){
                ss.putback(tmp);
                ss >> opnum;
                pos.push(opnum);
            }
            else{
                int opnum1 = pos.top();
                pos.pop();
                int opnum2 = pos.top();
                pos.pop();
                switch(tmp){
                    case '+':
                        pos.push(opnum1 + opnum2);
                        break;
                    case '-':
                        pos.push(opnum2 - opnum1);
                        break;
                    case '*':
                        pos.push(opnum1 * opnum2);
                        break;
                    case '/':
                        pos.push(opnum2 / opnum1);
                        break;
                }
            }
        }
        cout << pos.top() << endl;
        pos.pop();
    }
    return 0;
}
3:堆栈基本操作

总时间限制: 1000ms 内存限制: 65535kB

描述
依次读入序列元素1,2,…,n进栈,每进一个元素,机器可要求下一个元素进栈或弹栈,如此进行。给定一个输入序列,判断栈空时弹出的元素构成的序列是否可能等于给定的序列,如果是则输出栈的操作过程,否则输出“NO”。

输入
输入分两行
第一行为n的值(即序列元素个数)
第二行为给定的输入序列(序列元素均为整型)

输出
如果输入序列能够由题目规定的操作得到,则输出对栈的操作过程
否则直接输出“NO”

样例输入
7
4 5 3 6 2 7 1

样例输出
PUSH 1
PUSH 2
PUSH 3
PUSH 4
POP 4
PUSH 5
POP 5
POP 3
PUSH 6
POP 6
POP 2
PUSH 7
POP 7
POP 1

提示
给定序列中有可能有不在1…n之间的数字
思路:先判断是否合法,再写步骤(同时进行时空间超了,这波是用时间换空间

#include <iostream>
#include <string>
#include <stdio.h>
#include <vector>
#include <stack>
using namespace std;
int n = 0;
vector<int>v;
stack<int>s;
bool appear[1000001] = {};
bool isLegal(vector<int> & q){
    int pop_idx = 0, idx = 0;
    for(;idx < n; ++idx){
        s.push(idx + 1);
        while(!s.empty() && s.top() == q[pop_idx]){
            s.pop();
            ++pop_idx;
        }
    }
    return s.empty() && pop_idx == n;
    //模拟过后栈s应该是空的,同时进栈元素数idx和出栈元素数pop_idx应该相等
}

int main() {
    cin >> n;
    for(int i = 0; i < n; ++i){
        int tmp;
        cin >> tmp;
        if(tmp > n || tmp <= 0 || appear[tmp]){
            cout << "NO" << endl;
            return 0;
        }
        appear[tmp] = 1;
        v.push_back(tmp);
    }
    if(!isLegal(v)){
        cout << "NO" << endl;
        return 0;
    }
    int i = 1, j = 0;
    while(!s.empty())
        s.pop();
   
    while(j < n){
        if(s.empty() || s.top() != v[j]){
            cout << "PUSH " << i << endl;
            s.push(i);
            ++i;
        }
        else{
            cout << "POP " << s.top() << endl;
            s.pop();
            j++;
        }
    }
    return 0;
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个 SQL 语句,用于向借阅表中插入数据。该表包含以下字段:借阅编号、读者编号、书籍编号、借阅日期、归还日期、借阅状态。每条数据表示一次借阅记录。其中借阅编号、读者编号、书籍编号、借阅日期和借阅状态是必填项,归还日期为可选项,如果借阅状态为“已还”则必须填写归还日期。 具体插入的数据如下: - 借阅编号:100001,读者编号:123413,书籍编号:0001,借阅日期:2020-11-05,归还日期:NULL,借阅状态:借阅 - 借阅编号:100002,读者编号:223411,书籍编号:0002,借阅日期:2020-9-28,归还日期:2020-10-13,借阅状态:已还 - 借阅编号:100003,读者编号:321123,书籍编号:1001,借阅日期:2020-7-01,归还日期:NULL,借阅状态:过期 - 借阅编号:100004,读者编号:321124,书籍编号:2001,借阅日期:2020-10-09,归还日期:2020-10-14,借阅状态:已还 - 借阅编号:100005,读者编号:321124,书籍编号:0001,借阅日期:2020-10-15,归还日期:NULL,借阅状态:借阅 - 借阅编号:100006,读者编号:223411,书籍编号:2001,借阅日期:2020-10-16,归还日期:NULL,借阅状态:借阅 - 借阅编号:100007,读者编号:411111,书籍编号:1002,借阅日期:2020-9-01,归还日期:2020-9-24,借阅状态:已还 - 借阅编号:100008,读者编号:411111,书籍编号:0001,借阅日期:2020-9-25,归还日期:NULL,借阅状态:借阅 - 借阅编号:100009,读者编号:411111,书籍编号:1001,借阅日期:2020-10-08,归还日期:NULL,借阅状态:借阅

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值