这周一共四题。分别是括号序列,后缀表达式,队列安排,寄包柜。
先说第二题括号序列,这道题是唯一一道不用新知识就能做出来的题。
这道题的解题关键在于圆括号和方括号的区别以及标记与判定的结合
(其实最重要的是对题目的理解)
看这道题的第一遍,没看懂,第二遍,还是没看懂,后面反复观察输入输出才弄明白怎么回事。简而言之,从左往右读,读到')'和']'的时候开始往左读,读到第一个'('和'['时停止,如果匹配就标记两者,不匹配的话就不标记。读取字符串完毕后便直接按顺序输出,被标记的直接输出,没被标记的补全(比如'('和')'就补全成'()','['和']'就补全成'[]')然后输出。
至于圆括号和方括号的区别以及标记与判定的结合,我想的是分开处理圆括号和方括号,并且每次判定都加个int类型的数组来判定是否被标记(并且这样同时能解决如何标记的问题)
来看题解
#include <bits/stdc++.h>
using namespace std;
int A[1000]={0};
int main(){
char a[1000]={0};
cin.getline(a,1000);//输入
int len=strlen(a);
for(int i=0;i<len;i++){
if(a[i]==')'){//分开处理')'和']',但是方法一样
for(int k=i-1;k>=0;k--){
if(a[k]=='('&&A[k]==0){
A[k]=A[i]=1;//标记(在Int的数组里)
break;//跳出
}
if(a[k]=='['&&A[k]==0){
break;
}//不匹配
}
}
if(a[i]==']'){//同理
for(int k1=i-1;k1>=0;k1--){//处理']'
if(a[k1]=='['&&A[k1]==0){
A[k1]=A[i]=1;
break;
}
if(a[k1]=='('&&A[k1]==0){
break;
}
}
}
}
for(int j=0;j<len;j++){//处理输出
if(A[j]==1){
cout<<a[j];
}
else if(a[j]=='('||a[j]==')'){
cout<<'('<<')';
}
else
cout<<'['<<']';
}
return 0;
}
然后便是后缀表达式
这道题直接用栈,可以直接在读的时候判(注意减和除的情况)
#include <bits/stdc++.h>
using namespace std;
stack<int> n;
char ch;
int s,x,y;
int main()
{
while(ch!='@')
{
ch=getchar();
switch(ch)
{
case '+':x=n.top();n.pop();y=n.top();n.pop();n.push(x+y);break;
case '-':x=n.top();n.pop();y=n.top();n.pop();n.push(y-x);break;
case '*':x=n.top();n.pop();y=n.top();n.pop();n.push(x*y);break;
case '/':x=n.top();n.pop();y=n.top();n.pop();n.push(y/x);break;
case '.':n.push(s);s=0;break;
default :s=s*10+ch-'0';break;
}
}
printf("%d\n",n.top());
return 0;
}
后面是队列安排,这道题是链表的提高题。
读入每一个同学时,都把他左边和右边的同学更新;删除同学时,先把这个同学赋为0,再把他左边的同学连上右边的同学;最后找到排在最左边的同学,挨个输出。
#include <bits/stdc++.h>
using namespace std;
int a[100010][3],n,m;
//a[i][2]表示学号为i的同学右边同学的学号
//a[i][3]表示学号为i的同学左边同学的学号
int main()
{
cin>>n;
int j=1;
memset(a,0,sizeof(a)); a[1][1]=1;
for(int i=2;i<=n;i++)
{
int x,y;
cin>>x;
cin>>y;
a[i][1]=i;
if(y==0)
//插入左边
{
a[a[x][3]][2]=i; a[i][2]=x;
a[i][3]=a[x][3]; a[x][3]=i;
if(x==j) j=i;
//比较麻烦,要改链表
}
else
//插入右边
{
a[i][2]=a[x][2]; a[a[x][2]][3]=i;
a[x][2]=i; a[i][3]=x;
}
}
cin>>m;
for(int i=1;i<=m;i++)
{
int x;
cin>>x;
if(a[x][1]!=0)
//该同学还在
{
a[x][1]=0;
//踢掉
a[a[x][3]][2]=a[x][2];
a[a[x][2]][3]=a[x][3];
n--;
if(x==j) j=a[x][3];
}
}
int i=1,x=j;
while(i<=n)
{
cout<<a[x][1];
x=a[x][2]; i++;
}
return 0;
}
这道题还有双向链表的解法以及树的解法,但是我不懂双向链表和树,这里就不一一列举了。
最后一题用到了map,先看题。
乍一看,这用二维数组不就做出来了吗?但是横纵的数据大小都是10的5次方,乘一块那肯定得爆。于是转头寻找可以解出来的方法。既然二维数组因为内存过大而行不通,那不如试试vector。 但是又想到用vector的话在查询的时候还得遍历一遍,时间复杂度因此就更高了。因此想到这道题可以采用map的做法。
#include <bits/stdc++.h>
using namespace std;
int n,q,p,k;
map<long long,int>b;
long long i,j;
int main()
{
scanf("%d%d",&n,&q);
while(q--)
{
scanf("%d%d%d",&p,&i,&j);
if(p==1)
{
scanf("%d",&k);
b[i*1000000+j]=k;
}
else printf("%d\n",b[i*1000000+j]);
}
return 0;
}
由于两维数据都在1到10的5次方的范围内,故我们可以通过将一维数据乘上10的5次方再加上另一维数据,把两个int类型的数据压成一个long long类型的数据。这样便可以很精妙的建立映射关系。
感谢观看。