2020级数据结构荣誉可课第一次上机考试题解(线性表)
一、重复计数
在一个有限的正整数序列中,有些数会多次重复出现。请你统计每个数的出现次数,然后按数字在序列中第一次出现的位置顺序输出数及其次数。
题意:统计数列中每种数字出现的次数,并按照出现顺序输出。
思路:
一)、二重循环
这是没学数据结构之前最容易想到的方法,两次扫描。虽然简单但是时间复杂度为o(n2),至少开两个数组,空间复杂度较高。不是一个好的算法。在此不在展示代码。
二)、模拟链表
开一个结构体A,里面1存储数字和其出现的次数,边输入,边进行数据处理,加快了程序运行速度,从前往后扫描一遍若有重复数据,则num值+1,若没有则更新当前的结构体数组。
此作法时间复杂度为0(logn)。
完整代码
二、报数游戏
题意:约瑟夫问题的拓展,要求输出所有人出圈的的顺序。
思路:设置一个计步数的变量count,和出圈人数变量,每当count达到指定步长,将对应的编号输出并置标记‘0’,在清零count,更新出圈人数。
完整代码:
三、算术表达式的计算:
题意:输入一串算术表达式(带有括号),将其计算输出。、
思路:
可以采用栈来完成,利用栈的性质将中缀表达式转换为后缀表达式,根据优先级弹栈压栈。因为要识别运算符“+,-,*”,所以我们还要写计算函数和判断优先级的函数。
代码:
运算函数:
优先级函数:
关键代码:将中缀表达式转换为后缀表达式,我们需要两个栈一个存储运算符一个存储待运算的值或运算结果。
1)、判断将数字压入栈q中
2)、将运算符压入栈s中,并随即将其转换为后缀运算符的形式:
3)、完整代码:
#include<stack>
#include<iostream>
#include<math.h>
#include<ctype.h>
using namespace std;
int calculate(int d1,char t,int d2);
int jugepre(char x);
int main()
{ char a[1001];
cin>>a;
stack<char> s;
stack<int> q;
int i=0,d=0;
while(a[i]!='=')
{ char x=a[i];
if(x>='0'&&x<='9')
{
d=x-'0';
while(a[i+1]!='\0'&&a[i+1]>='0'&&a[i+1]<='9')
{
x=a[++i];
d=d*10+(x-'0');
}
q.push(d);
}
else
{
if(s.empty()||x=='(') {s.push(x);}
else if(x==')')
{
while(s.top()!='('&&!s.empty())
{
int d2=q.top();q.pop();
int d1=q.top();q.pop();
char t=s.top();s.pop();
if(t=='/'&&d2==0)
{
cout<<"NaN";
return 0;
}
int al=calculate(d1,t,d2);
q.push(al);
}
s.pop();
}
else if(jugepre(x)>jugepre(s.top())) s.push(x);
else if(jugepre(x)<=jugepre(s.top())) {
while(!s.empty()&&(jugepre(x)<=jugepre(s.top())))
{
int d2=q.top();q.pop();
int d1=q.top();q.pop();
char t=s.top();s.pop();
if(t=='/'&&d2==0)
{
cout<<"NaN";
return 0;
}
int al=calculate(d1,t,d2);
q.push(al);
}
s.push(x);
}
}
i++;
}
while(!s.empty())
{
int d2=q.top();q.pop();
int d1=q.top();q.pop();
char t=s.top();
s.pop();
if(t=='/'&&d2==0)
{
cout<<"NaN";
return 0;
}
int al=calculate(d1,t,d2);
q.push(al);
}
cout<<q.top();
return 0;
}
int jugepre(char x)
{
if(x=='(') return 0;
else if(x=='*'||x=='/') return 2;
else if(x=='+'||x=='-') return 1;
}
int calculate(int d1,char t,int d2)
{
if(t=='^')
{
//cout<<int(pow(d1,d2))<<endl;
return int(pow(d1,d2));
}
else if(t=='*')
return d1*d2;
else if(t=='/')
return d1/d2;
else if(t=='+')
return d1+d2;
else if(t=='-')
return d1-d2;
}
四、最喜爱序列
题意:一个含有N个整数的序列,求区间长度不超过m的区间中,区间内值和的最大值,以及该区间。若有多个则取第一个;
思路:才开始没有看清题意以为区间为定长暴力求解,只拿了40分,后来学习了其他同学的算法。采用单调队列自己重新写了一遍后,才通过。
知识点 :单调队列
单调队列。维护一个区间正确且单调
递增的队列,每次队首就是当前区间的最值
1.
单调性的维护
:当前元素和队尾元素比较,
若队尾
元素大于当前元素,队尾元素出队
;重复处理,
直
到队空或队尾元素小于当前元素;当前元素入队;
// f
队首,
r
队尾后空位
while(f<r && a[que[r-1]] > a[i] ) r--;
que[r++] = i;
2.
区间的维护:
若队首元素的位置不在区间内
,则队
首元素出队;重复处理,直到队首元素在区间内
while( f<r && que[f] < i-m+1 ) f++;
代码:
#include<iostream>
#include<queue>
using namespace std;
int main(void)
{ int a[600000];
deque<int> s;
int l, r;
int i=0, j=0,n=0, m=0;
cin>>n>>m;
a[0] = 0;
for (i = 1; i <= n; i++)
{
cin>>a[i];
a[i] += a[i - 1];
}
int max = 0;
while (!s.empty())
s.pop_back();
s.push_front(0);
for (i = 1; i <= n; i++)
{
while ( a[s.front()] > a[i] &&!s.empty() )
{
s.pop_front();
}
s.push_front(i);
while ( m<i - s.back() &&!s.empty())
{
s.pop_back();
}
if(max< a[i] -a[s.back()])
{
max = a[i] - a[s.back()];
l = s.back()+1;
r = i;
}
}
cout<<max<<" "<<l<<" "<<r<<"\n";
return 0;
}