JLU-数据结构荣誉课-第一次实验-解题报告

  • 一、重复计数
    • 题目
    • 思路
    • 参考代码
  • 二、报数游戏
    • 题目
    • 思路
    • 参考代码
  • 三、算术表达式计算
    • 题目
    • 思路
    • 参考代码
  • 四、最喜爱的序列
    • 题目
    • 思路
      • 单调队列
    • 参考代码
  • 总结

一、重复计数

题目

在一个有限的正整数序列中,有些数会多次重复出现。请你统计每个数的出现次数,然后按数字在序列中第一次出现的位置顺序输出数及其次数。

输入格式:

第1行,1个整数N,表示整数的个数,(1≤N≤50000)。

第2行,N个正整数,每个整数x 都满足 1 ≤ x ≤2000000000。

输出格式:

若干行,每行两个用一个空格隔开的数,第一个是数列中出现的数,第二个是该数在序列中出现的次数。

输入样例:

  • 12
  • 8 2 8 2 2 11 1 1 8 1 13 13

输出样例:

  • 8 3
  • 2 3
  • 11 1
  • 1 3
  • 13 2

题意:

统计序列中各元素出现的频率,并按照原来的相对顺序依次输出。

思路

解法一:

  1. 统计频率:
    由于题目中有规定整数的个数,可以开辟一个对应大小的数组,每次读入数组的下标,将对应的元素+1,用空间换时间。

  2. 按照原相对顺序输出:
    我们可以采用一个容器来保存之前出现过的元素下标,最后再按照原顺序输出。由于先入容器的下标要先出容器,所以我们容器我们选择队列。

解法二:

  1. 先无脑读入所有数据,同时用队列记录元素值出现的相对顺序,之后对数据进行排序,最后输出该值的数量。
  2. sort()排序:STL中自带的一种高效的标准排序算法,可以排序任意线性存储的容器。需要的三个参数为:①容器的起始迭代器;②容器的结束迭代器;③排序标准(二元谓词),默认为less从小到大。
  3. lower_bound():在[begin,end)进行二分查找,返回大于或等于key的第一个元素位置的迭代器。如果所有元素都小于key,则返回end的位置迭代器。
  4. upper_bound():在[begin,end)进行二分查找,查找的关键字的上界,返回大于key的第一个元素位置的迭代器。
  5. 要注意的是,由于使用了二分查找,查找的对象应该都是有序的。

参考代码

解法一:

#include "iostream"
#include "queue"
using namespace std;queue<int> q;int Num;int a[500000];//全局变量,初始即全为0
int main()
{cin>>Num;int index;for(int i=0;i<Num;i++){cin>>index;if(!a[index])//若a[index]为零,说明index第一次出现,index入栈q.push(index);a[index]++;}while(q.size()!=1)//由于输出格式有要求,我们在队列剩余一个元素时停止输出{index=q.front();q.pop();cout<<index<<" "<<a[index]<<endl;}index=q.front();//最后一个元素输出时最后无多余回车q.pop();cout<<index<<" "<<a[index];
}

解法二:

#include "iostream"
#include "algorithm"
#include "queue"
using namespace std;int a[50001];
int N;queue<int> q;int main()
{cin>>N;for(int i=1;i<=N;i++){cin>>a[i];if(find(a,a+i,a[i])==a+i)//检测是否a[i]之前是否存在,这个算法就是遍历,效率不高q.push(a[i]);}sort(a+1,a+N+1);int val;while(q.size()!=1)//由于输出格式有要求,在队中元素剩一个时停止输出{val=q.front();q.pop();cout<<val<<" "<<upper_bound(a+1,a+N+1,val)-lower_bound(a+1,a+N+1,val)<<endl;}val=q.front();q.pop();cout<<val<<" "<<upper_bound(a+1,a+N+1,val)-lower_bound(a+1,a+N+1,val);
}

二、报数游戏

题目

n个人围成一圈,从1开始依次编号,做报数游戏。 现指定从第1个人开始报数,报数到第m个人时,该人出圈,然后从其下一个人重新开始报数,仍是报数到第m个人出圈,如此重复下去,直到所有人都出圈。总人数不足m时将循环报数。请输出所有人出圈的顺序。

输入格式:

一行,两个整数n和m。n表示游戏的人数,m表示报数出圈的数字,1≤n≤50000,1≤m≤100。

输出格式:

一行,n个用空格分隔的整数,表示所有人出圈的顺序。

输入样例:

  • 5 2

输出样例:

  • 2 4 1 5 3

题意:

经典的约瑟夫环问题。

思路

由于算法需要高效,因此采用链表结构。构建具有哨兵结点的循环链表,每次出圈便去掉一个结点,直到结点全部去除。

参考代码

#include "iostream"
using namespace std;struct cell
{int data;cell *next;
};int N;
int M;int main()
{cin>>N>>M;cell *head,*tmp,*tail;head=tail=new cell;//创建哨兵结点for(int i=0;i<N;i++)//构建单向链表{tmp=new cell;tmp->data=i+1;tail->next=tmp;tmp->next=NULL;tail=tmp;}tail->next=head->next;//单向链表成环tmp=head;//以下tmp为要删除(出圈)的结点,p为tmp的前驱结点cell *p=NULL;while(N!=1)//由于格式有要求,所以在N=1时停止输出{for(int i=0;i<M;i++)//寻找要删除的结点{p=tmp;tmp=tmp->next;}cout<<tmp->data<<" ";//输出删除的结点p->next=tmp->next;//删除结点//delete tmp;//这里怕多次调用delete超时,所以没写tmp=p;//将tmp重置到前一位N--;//人数-1}cout<<tmp->next->data<<endl;//输出最后的结点//注意tmp指向的是上一个删除节点的前驱,要删除的结点为上一个删除结点的后继,因此删除的是tmp->next->data
}

三、算术表达式计算

题目

算术表达式按中缀给出,以=号结束,包括+,-,*,/四种运算和(、)分隔符。运算数的范围是非负整数,没有正负符号,小于等于109

计算过程中,如果出现除数为0的情况,表达式的结果为"NaN" ; 如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。 输入保证表达式正确。

输入格式:

一行,包括1个算术表达式。算术表达式的长度小于等于1000。

输出格式:

一行,算术表达式的值 。

输入样例:

  • (1+30)/3=

输出样例:

  • 10

题意:

计算中缀表达式的值,除数为0时,需要特别处理。

思路

  1. 我们需要两个栈,一个为数字栈,用来储存遇到的数字,一个为符号栈,用来储存遇到的符号。

  2. 与最原始的一位数字计算不同,本题中的数字不仅仅为一位数字。当读到数字字符时,可以循环读入数字字符,并根据sum=sum*10+(now-‘0’)来算出该大于一位的数字。

  3. 解决大于一位的数字之后,接着要考虑如何计算表达式。有两种思路:①先将中缀表达式转换成后缀表达式,再计算后缀表达式(与后缀表达式相关内容可见本文最后)。②边读边计算。这里主要介绍第二种方法。

  4. 当读入数字时,直接压入数字栈即可。当遇到符号时,有四种情况:①遇到左括号,直接入栈(因为左括号表示当前位置后面的数字要先算出来,所以此处不需要任何操作);②遇到±*/,不断取栈顶符号,如果栈顶符号的优先级大于或等于当前符号的优先级,则处理栈顶符号(因为若栈顶符号的优先级不小于当前符号,说明栈顶符号此时已经可以计算了)(具体过程为取数字栈的两个数据,检测符号,做相应的运算后,将结果再压入数字栈);③遇到右括号,不断取栈顶符号,并处理,直到遇到左括号停止;④遇到结束符号(本题为等号),不断处理栈顶符号即可(因为之前已经将能计算的全部计算,最后符号栈中符号的优先级关系一定符合正常运算)。

  5. 需要注意的问题
    遇到四种运算符时,一定要循环处理前面遇到的优先级大于或等于其的运算符,不要只处理优先级大于其的运算符,否则有反例:计算1-2-3,由于采用栈,所以计算顺序为倒序,则程序的计算过程为1-2-3=1-(-1)=2显然是错的。

  6. 具体演示,计算4-2*3-(3-4-5)=的值(由于*为特殊字符,演示中用×代替)

  • 4 -2×3-(3-4-5)= 4入数字栈(4)
  • 4 - 2×3-(3-4-5)= 检测符号栈顶,-入符号栈(-)
  • 4- 2 ×3-(3-4-5)= 2入数字栈(4 2)
  • 4-2 × 3-(3-4-5)= 检测符号栈顶,-优先级小于×,×入符号栈(- ×)
  • 4-2× 3 -(3-4-5)= 3入数字栈(4 2 3)
  • 4-2×3 - (3-4-5)= 检测符号栈顶,×优先级大于-,处理乘号(2,3出数字栈,×出符号栈,2×3入数字栈),此时数字栈(4 6),符号栈(-);再次检测符号栈顶,-优先级等于-,处理减号,此时数字栈(-2),符号栈();当前符号入符号栈(-)
  • 4-2×3- ( 3-4-5)= 左括号直接入栈(- ()
  • 4-2×3-( 3 -4-5)= 3入数字栈(-2 3)
  • 4-2×3-(3 - 4-5)= 检测符号栈顶,(优先级小于-,当前符号入符号栈(- ( -)
  • 4-2×3-(3- 4 -5)= 4入数字栈(-2 3 4)
  • 4-2×3-(3-4 - 5)= 检测符号栈顶,-优先级等于-,处理减号,此时数字栈(-2 -1),符号栈(- ();当前符号入符号栈(- ( -)
  • 4-2×3-(3-4- 5 )= 5入数字栈(-2 -1 5)
  • 4-2×3-(3-4-5 )= 遇到右括号,开始循环处理符号,直到遇到左括号。第一次处理后,符号栈(- ( ),数字栈(-2 -6);第二次处理遇到最括号,处理停止,此时符号栈(-),数字栈(-2,-6)
  • 遇到等号,处理所有符号,最终数字栈为(4)即为答案。

参考代码

#include "iostream"
#include "map"
#include "stack"
using namespace std;map<char,int> Pro;//用来储存符号优先级stack<int> Num;//数字栈
stack<char> Oper;//符号栈//用来记录大于1位整数的变量
int Flag;//某种标志
int s;//最终的整数值inline void Calculate(char oper)//根据符号进行计算,并将结果入栈
{int x,y;x=Num.top();Num.pop();y=Num.top();Num.pop();if(oper=='+')Num.push(y+x);else if(oper=='-')Num.push(y-x);else if(oper=='*')Num.push(y*x);else if(oper=='/'){if(!x)//除数为0{cout<<"NaN";exit(0);}Num.push(y/x);}
}int main()
{//建立符号间的优先级Pro.insert(make_pair('#',-1));Pro.insert(make_pair('(',0));Pro.insert(make_pair('+',1));Pro.insert(make_pair('-',1));Pro.insert(make_pair('*',2));Pro.insert(make_pair('/',2));Oper.push('#');//压栈符号char ch;cin>>ch;while(ch!='='){while(ch>='0'&&ch<='9')//处理大于1位整数{s=s*10+ch-'0';Flag=1;//标志此时检测到了数字cin>>ch;}if(Flag)//之前检测到了数字,压入数字,Flag和s归位{Num.push(s);Flag=0;s=0;}if(ch=='=')//如果数字之后是‘=’直接退出循环break;if(ch=='(')//左括号优先级最低,直接入栈Oper.push(ch);else if(ch==')')//检测到右括号,不断计算,直到遇到左括号{char oper=Oper.top();while(oper!='('){Oper.pop();Calculate(oper);oper=Oper.top();}Oper.pop();//弹出左括号}else if(ch=='+'||ch=='-'||ch=='*'||ch=='/')//检测到四种运算符处理前面所有优先级不大于ch的符号{char oper=Oper.top();while(Pro[oper]>=Pro[ch]){Oper.pop();Calculate(oper);oper=Oper.top();}Oper.push(ch);//压入当前符号}cin>>ch;}while(Oper.size()!=1)//处理剩余的符号,直到遇到压栈符号'#'{char oper=Oper.top();Oper.pop();Calculate(oper);}cout<<Num.top();
}

四、最喜爱的序列

题目

小唐这段时间在研究序列。拿来N个整数的序列,他给序列中的每个整数都赋予一个喜爱值。喜爱值也是整数,有正有负,越大表明越喜欢。他想知道,如何从序列中连续取最多m个数,他获得喜爱值最大。1≤N≤500000,1≤m≤N。

输入格式:

第一行是两个整数N,m。分别代表序列中数的个数以及能取的最多个数。

第二行用空格隔开的N个整数,第i个整数Li代表他对第i个数的喜爱值。│Li│≤1000。

输出格式:

一行,三个数,表示获得最大喜爱值,及第一个取最大喜爱值的区间。

输入样例:

  • 5 2
  • 1 4 5 2 3

输出样例:

  • 9 2 3

题意:

输出 至多m长度的区间内 和的 最大值。

思路

本题是一个典型的利用单调队列求解的题目。

单调队列

维护一个区间正确,且单调递增的队列,每次队首都是当前区间的最小值。

  1. 单调性的维护:当前元素与队尾元素比较,若队尾元素大于当前元素,队尾元素出队;重复处理,直到队空或队尾元素小于当前元素。
  2. 区间的维护:若队首元素的位置不在区间内(当前元素下标-队首元素下标>区间长度),则队首元素出队;重复处理。

参考代码

#include "iostream"
using namespace std;struct Cell
{int data;//记录元素值int num;//记录下标
};class MyDeque//自定义双端队列
{Cell a[500001];int Num;//队列中元素的个数,用来给Cell中的num赋值用int top;//队列头指针int rear;//队列尾指针
public:MyDeque():top(0),rear(0),Num(0){}void push(int x)//后端入队{a[rear].data=x;a[rear].num=++Num;rear++;}int peek_backdata(){ return a[rear-1].data; }//查看队尾元素值int peek_backnum(){ return a[rear-1].num; }//查看队尾下标void pop_back(){ rear--; }//后端出队int peek_frontdata(){ return a[top].data; }//查看队头元素值int peek_frontnum(){ return a[top].num; }//查看队头下标void pop_front(){ top++; }//前端出队int empty(){ return top==rear; }//判断队空
};int M,N;
int a[500001];//实际储存前n项的和,由于是全局变量,a[0]初始时为0
MyDeque d;int Max=-500000001;//最大值,开始时初始化为最小值
int top=1;//左区间
int rear=1;//右区间int main()
{cin>>N>>M;for(int i=1;i<=N;i++){cin>>a[i];//依次读入数据a[i]+=a[i-1];//记录前n项和,方便以后求某区间内的和}for(int i=0;i<N;i++){//队列非空,不断检测队尾元素,弹出大于当前元素的结点while(!d.empty()&&d.peek_backdata()>a[i])d.pop_back();d.push(a[i]);//当前元素入队//检测队头元素的下标,维护在要求的区间内while(d.peek_backnum()-d.peek_frontnum()>=M)d.pop_front();int tmp=a[i+1]-d.peek_frontdata();//计算当前区间内的元素之和if(Max<tmp)//判断是否更新最大值{Max=tmp;top=d.peek_frontnum();rear=d.peek_backnum();}}cout<<Max<<" "<<top<<" "<<rear;
}

总结

  1. 一种map的用法——处理优先级。此处map的用法类似于一种特殊的数组,数组的下标可以是任意类型的值,数组的值也可以是任意类型的值。

  2. 与第三题相关的题目——中缀表达式转后缀表达式
    参考代码:

    #include "iostream"
    #include "vector"
    #include "map"
    #include "stack"
    using namespace std;vector<string> ans;//储存后缀表达式
    stack<char> Oper;//符号栈
    map<char,int> pro;//处理优先级inline string String(char c)//char类型转string类型
    {string s(1,c);return s;
    }int main()
    {//设置优先级pro.insert(make_pair('+',0));pro.insert(make_pair('-',0));pro.insert(make_pair('*',1));pro.insert(make_pair('/',1));pro.insert(make_pair('(',-1));char str[21];int i=0;cin>>str;int len=strlen(str);while(i<len){int Flag=0;char tmp=str[i];string s;while(tmp>='0'&&tmp<='9')//处理多位数字{s=s+tmp;i++;tmp=str[i];Flag=1;}if(Flag)//数字直接入栈ans.push_back(s);//按照运算顺序,符号依次入栈if(tmp=='(')Oper.push(tmp);else if(tmp==')'){char oper=Oper.top();while(oper!='('){Oper.pop();ans.push_back(String(oper));oper=Oper.top();}Oper.pop();}else{char oper;while(!Oper.empty()){oper=Oper.top();if(pro[oper]>=pro[tmp]){Oper.pop();ans.push_back(String(oper));}elsebreak;}Oper.push(tmp);}i++;}while(Oper.size()!=1)//将剩余的等号以外的符号入栈{char oper=Oper.top();Oper.pop();ans.push_back(String(oper));}for(vector<string>::iterator it=ans.begin();it!=ans.end();it++)cout<<*it<<" ";cout<<endl;return 0;
    }
    

数据结构荣誉课-第一次实验-解题报告相关推荐

  1. 数据结构第七次上机实验-解题报告

    数据结构第七次上机实验-解题报告 7-1 序列调度 (100 分) 题目 思路 参考代码 7-2 最大最小差 (100 分) 题目 思路 参考代码 7-3 二叉树最短路径长度 (100 分) 题目 思 ...

  2. JLU第三次数据结构上机实验解题报告

    T1:二叉树最长路径 题目 给定一棵二叉树T,求T中的最长路径的长度,并输出此路径上各结点的值.若有多条最长路径,输出最右侧的那条. INPUT 第1行,1个整数n,表示二叉树有n个结点. 第2行,2 ...

  3. 安徽科技学院2017-2018-1学期15电信12班《Java编程技术》课下作业~解题报告

    A: 筛排处理 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 422 Solved: 143 上一题SubmitStatus标签打分编辑题目信息编辑测试 ...

  4. 20172329 2017-2018-2 《程序设计与数据结构》实验五报告

    这是这学期最后一次实验了,也是学到了很多东西,希望自己可以可以善始善终,加油! 让我们开始这一篇博客吧! 20172329 2017-2018-2 <程序设计与数据结构>实验五报告 课程: ...

  5. 20172329 2017-2018-2 《程序设计与数据结构》实验四报告

    20172329 2017-2018-2 <程序设计与数据结构>实验四报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 王文彬 学号:20172329 实验教师:王 ...

  6. 20172305 2017-2018-2 《程序设计与数据结构》实验三报告

    20172305 2017-2018-2 <程序设计与数据结构>实验三报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 谭鑫 学号:20172305 实验教师:王志 ...

  7. 20172307 2018-2019-1 《程序设计与数据结构》实验3报告

    20172307 2018-2019-1 <程序设计与数据结构>实验3报告 课程:<程序设计与数据结构> 班级: 1723 姓名:黄宇瑭 学号:07 实验教师:王志强 实验日期 ...

  8. 20172318 2017-2018-2 《程序设计与数据结构》实验4报告

    20172318 2017-2018-2 <程序设计与数据结构>实验4报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 陆大岳 学号:20172318 实验教师:王 ...

  9. 20172329 2017-2018-2 《程序设计与数据结构》实验一报告

    20172329 2017-2018-2 <程序设计与数据结构>实验一报告 课程:<程序设计与数据结构> 班级: 1723 姓名: 王文彬 学号:20172329 实验教师:王 ...

最新文章

  1. python 、example
  2. php重定向 htaccess文件的编写
  3. 关于文件描述符的问题的解决
  4. Java动态代理代码案例:使用cglib实现对无接口的类进行动态代理
  5. 历经3年的打磨,数据构建及管理平台Dataphin增加了什么新功能?
  6. 给自己的Blog 上添加定制的搜索引擎
  7. leetcode 387 C++数组做法
  8. matlab fft函数说明_关于“如何使用FFT计算天线阵列方向图”学习资料总结
  9. web前端学习之HTML
  10. 斐波那契数(动态规划和递归)
  11. numpy中矩阵的转置_NumPy矩阵transpose()-Python中数组的转置
  12. 深圳学校积分计算机,深圳计算机 初级证书入户积分吗,看这里就知道了!
  13. 张亮:十万级并发任务调度框架 ElasticJob 的定位与设计理念
  14. meteor使用简介
  15. 台式计算机调亮度快捷键,处理电脑调亮度快捷键如何调整屏幕亮度呢?
  16. permissions is only granted to system apps
  17. 转载(工信部):张欣 辽宁奇辉电子系统工程有限公司
  18. oracle+dba+网课,[Oracle] 蓬动Oracle教程 DBA培训视频实战精品课及开发转Oracle 共52课...
  19. hashcat破解WiFi显示No hashes loaded的解决方法
  20. 二进制1010.0101转换为十进制

热门文章

  1. python数据采集8-自然语言处理
  2. 如何在 Excel 表格中查找数据
  3. 雷军:相信自己,一往无前(MI10周年演讲精彩语录)
  4. 面试题:两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
  5. win10专业版电脑不能局域网访问win10家庭版
  6. 信息系统项目管理师知识总结
  7. python制作搜索工具,深挖电脑里的小九九
  8. TOE(TCP/IP Offload Engine)网卡与一般网卡的区别
  9. React之Ref如何去使用?
  10. Chrome 实用渗透测试插件合集