1. 算术表达式计算
任务: 计算算术表达式的值。
算术表达式按中缀给出,以=号结束,包括+,-,,/四种运算和(、)分隔符。运算数的范围是非负整数,没有正负符号,小于等于109 。
计算过程中,如果出现除数为0的情况,表达式的结果为”NaN” ; 如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。
输入保证表达式正确。输入格式:
一行,包括1个算术表达式。算术表达式的长度小于等于1000。
输出格式:
一行,算术表达式的值 。
代码长度限制-16 KB
时间限制-400 ms
内存限制-64 MB
完整代码:
引入操作符栈将中缀表达式转化为后缀表达式,然后根据运算符的优先级和括号确定出栈顺序
#include<iostream>
#include<string>
#include<stack>
using namespace std;
//暂时用STL,之后尝试自己封装栈
string s;//输入算数表达式
stack<int> num;//操作数栈
stack<char> oper;//运算符栈
int pos = 0;//计数
int compare(char x, char y);
int calculate(int x, char a, int y);
int main() {
cin >> s;
while (pos <= s.length()) {
char c = s[pos];
if (c >= '0' && c <= '9') {//操作数
int m = c - '0';
for (pos++; s[pos] >= '0' && s[pos] <= '9'; pos++) {
m = m * 10 + s[pos] - '0';
}
num.push(m);
}
else if (c == '=') {//等号输出结果
while (!oper.empty()) {
int x, y;
char tmp = oper.top(); oper.pop();
y = num.top(); num.pop();
x = num.top(); num.pop();
num.push(calculate(x, tmp, y));
}
cout << num.top();
exit(0);
}
else if (c == '(') {//左括号,直接压入
oper.push(c);
pos++;
}
else if (c != ')') {//运算符,比较优先级确定是否计算
while (!oper.empty() && compare(oper.top(), c) >= 0) {
char tmp1;
tmp1 = oper.top(); oper.pop();
int x, y;
y = num.top(); num.pop();
x = num.top(); num.pop();
num.push(calculate(x, tmp1, y));
}
oper.push(c);
pos++;
}
else {//右括号,计算两括号间内容
while (oper.top() != '(') {
char tmp = oper.top(); oper.pop();
int x, y;
y = num.top(); num.pop();
x = num.top(); num.pop();
num.push(calculate(x, tmp, y));
}
oper.pop();
pos++;
}
}
return 0;
}
int calculate(int x, char a, int y) {
if (a == '*')return x * y;
else if (a == '+')return x + y;
else if (a == '-') return x - y;
else {
if (y == 0) {
cout << "NaN";
exit(0);
}
return x / y;
}
}//具体计算
int compare(char x, char y) {
if (x == '*' || x == '/')return 1;
if ((x == '+' || x == '-') && (y == '*' || y == '/'))return -1;
if ((x == '+' || x == '-') && (y == '+' || y == '-'))return 1;
if (x == '(') return -1;
}//比较优先级
2. 括号配对
高级语言程序设计中的各种括号应该匹配,例如:“(” 与 “)”匹配、“[”与 “]” 匹配、“{”与 “}” 匹配等。
输入一字符文件,判断其中的括号是否匹配。假设括号没有优先级差别。输入格式:
多行,字符个数不超过 65536。
输出格式:
一个单词,表示字符文件中括号匹配的结果,匹配输出“yes”,否则输出“no”.
代码长度限制-16 KB
时间限制-10 ms
内存限制-1 MB
完整代码:
遇到闭括号时,应考察其与最近为匹配的开括号是否匹配,匹配则弹出,继续考察。
注意字符文件的处理方法
#include<cstdio>
#include<iostream>
using namespace std;
char fuhao[65536];
int top = 0;
int result = 1;
int main()
{
char a;
while (cin >> a)
{
if (a == '(' || a == '{' || a == '[')
{
fuhao[top] = a;
top++;
}
else if (a == ')' || a == '}' || a == ']')
{
if (a == ')')
{
if (fuhao[--top] != '(')
{
//cout << "?";
result = 0;
}
}
else if (a == '}')
{
if (fuhao[--top] != '{')
{
//cout << "s";
result = 0;
}
}
else if (a == ']')
{
if (fuhao[--top] != '[')
{
//cout << "a";
result = 0;
}
}
}
}
if (top != 0)
{
result = 0;
}
if (result == 0)
{
printf("no");
}
else
{
printf("yes");
}
return 0;
}
3. Blash数集
大数学家高斯小时候偶然发现一种有趣的自然数集合Blah。以a为基的集合Ba定义如下:
- a是集合Ba的基,且a是Ba的第一个元素;
- 若x在集合Ba中,则2x+1和3x+1也都在Ba中;
- 没有其它元素在集合Ba中。
现在小高斯想知道如果将集合Ba中元素按照升序排列,第n个元素会是多少?输入格式:
多行,每行包括两个数,集合的基a(1<=a<=50))以及所求元素序号n(1<=n<=1000000)
输出格式:
对于每个输入,输出集合Ba的第n个元素值
代码长度限制-16 KB
时间限制-1000 ms
内存限制-10 MB
完整代码:
利用队列模拟,分别构成两个递增队列,每次从两个队列中分别取最小元素作为当前元素
#include<iostream>
#include<queue>
using namespace std;
int a, n;
int main()
{
while (cin >> a >> n)
{
queue<int>q1, q2;//两个队列
n--;//默认基数已出队
while (n!=0)
{
q1.push(2 * a + 1);
q2.push(3 * a + 1);
if (q1.front() < q2.front())
{
a = q1.front();
q1.pop();
}
else if (q1.front() > q2.front())
{
a = q2.front();
q2.pop();
}
else
{
a = q1.front();
q1.pop();
q2.pop();
}
n--;
}
cout << a << endl;
}
return 0;
}
4. 左侧最近小数
对N个非负整数的序列,查询元素Ai 左侧最近的小于Ai 的整数(1≤i≤N),如果不存在,输出 -1
输入格式:
第1行,1个整数N,表示整数的个数,(1≤N≤100000)。
第2行,N个整数,每个整数x 都满足 0 ≤ x ≤2000000000。
输出格式:
1行,N个整数,表示每个元素Ai左侧最近的小于Ai 的整数(1≤i≤N)。
代码长度限制-16 KB
时间限制-100 ms
内存限制-2 MB
完整代码:
维护一个单调递增的栈,使用当前元素维护单调性后,栈顶即为所求。
单调性维护:当前元素和栈顶元素比较,栈顶大则出栈,重复处理直到栈空或栈顶小于当前元素
#include <iostream>
#include <stack>
using namespace std;
int main() {
int N;
cin >> N;
stack<int> stack;
int* q = new int[N];
for (int i = 0; i < N; i++) {
cin >> q[i];
}
for (int i = 0; i < N; i++) {
while (!stack.empty() && stack.top() >= q[i]) {
stack.pop();
}
if (stack.empty()) {
cout << -1 ;
if(i!=N-1)
cout<<" ";
}
else {
cout << stack.top() ;
if(i!=N-1)
cout<<" ";
}
stack.push(q[i]);
}
delete[] q;
return 0;
}
5. 区间最小值
对N个整数的序列,从左到右连续查询 M 长度子序列 Ai,Ai+1,...,Ai−M+1 (1≤i,M≤N)的最小值。
输入格式:
第1行,两个整数:N和M,表示整数的个数和区间长度,1≤N≤100000.
第2行,N个整数,每个整数x 都满足 │x│≤2000000000。输出格式:
1行, 用空格分隔的N-M+1个整数,对应从左到右所有连续M长度子序列的最小值。
代码长度限制-16 KB
时间限制-100 ms
内存限制-2 MB
完整代码:
维护一个区间正确且单调递增的队列,每次队首就是区间最值
单调性维护:队尾大于当前元素,队尾元素出队,直到队空或队尾元素小于当前元素,当前入队
区间维护:若队首元素不在区间内则出队,直到在区间内
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100010;
int a[N],b[N];
int l=0,r=1;
int n,m;
int main()
{
cin>>n>>m;
b[0]=1;
for(int i=1;i<=n;i++)
{
//cout<<i<<endl;
scanf("%d",&a[i]);
if(i!=1)
{
while(a[i]<=a[b[r-1]]&&r>l)r--;
b[r]=i;
r++;
}
if(i<m)continue;
while(b[l]<=i-m)l++;
printf("%d",a[b[l]]);
if(i!=n)printf(" ");
}
return 0;
}
注意:
cin可以用来从键盘输入数据;将标准输入定向为文件后,cin也可以用来从文件中读入数据。在输入数据的多少不确定,且没有结束标志的情况下。若是从文件中读取数据,到达文件末尾就读取结束了。从控制台读取数据时,可以通过输入特殊的控制字符:
在window系统中,通过键盘输入时,按Ctrl+Z组合键后再按回车键,就代表输入结束。
在UNIX/Linux/Mac OS系统中,Ctrl+D代表输入结束。