数据结构PTA练习题2

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定义如下:

  1. a是集合Ba的基,且a是Ba的第一个元素;
  2. 若x在集合Ba中,则2x+1和3x+1也都在Ba中;
  3. 没有其它元素在集合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代表输入结束。
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值