数据结构荣誉课---第一次实验解题报告
Posted qq_52090648
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构荣誉课---第一次实验解题报告相关的知识,希望对你有一定的参考价值。
一,重复计数
题目
在一个有限的正整数序列中,有些数会多次重复出现。请你统计每个数的出现次数,然后按数字在序列中第一次出现的位置顺序输出数及其次数。
输出格式:
若干行,每行两个用一个空格隔开的数,第一个是数列中出现的数,第二个是该数在序列中出现的次数。
输入样例:
在这里给出一组输入。例如:
输出样例:
在这里给出相应的输出。例如:
解题思路
用了O(n^2)的方法,在两个平台上都满分通过了,所以只写了这个方法的解题思路。
- 开辟两个长度为n的数组,一个记录读入的数据,另一个所有元素初始化为0,记录读入的数据是不是第一次出现,如果不是第一次出现,将相应的0改为1。
- 初始化一个变量count为1,数字重复出现,则count++,循环结束时将count打印出来,再次初始化为1,为下一个数据的统计频率做准备。
代码
#include<stdio.h>
#include<stdlib.h>
int main() {
int N;
int a[50001], b[50001] = { 0 };
int count=1, i, j;
scanf("%d", &N);
for (i = 0; i < N; i++) {
scanf("%d", &a[i]);
}
for (i = 0; i < N; i++) {
if (b[i]==0) {
count = 1;//初始化
for (j = i + 1; j < N; j++) {
if (a[i] == a[j]) {
b[j] = 1;//标记出现过的数据
count++;//统计频率
}
}
printf("%d %d\\n", a[i], count);
}
}
}
二,报数游戏
题目
n个人围成一圈,从1开始依次编号,做报数游戏。 现指定从第1个人开始报数,报数到第m个人时,该人出圈,然后从其下一个人重新开始报数,仍是报数到第m个人出圈,如此重复下去,直到所有人都出圈。总人数不足m时将循环报数。请输出所有人出圈的顺序。
输入格式:
一行,两个整数n和m。n表示游戏的人数,m表示报数出圈的数字,1≤n≤50000,1≤m≤100.
输出格式:
一行,n个用空格分隔的整数,表示所有人出圈的顺序
输入样例:
在这里给出一组输入。例如:
输出样例:
解题思路
- 这个题是约瑟夫环问题,比较简单。
- 注意当数到第n个人时将i重置为0.
- 老师说采用链表结构会更高效,但我还没有试。
if (i == n) {
i = 0; //从头开始数
}
代码
#include <stdio.h>
void left(int* a,int n,int m) {
int out = 0,count = 0,i = 0;
int *p = a;
int num = 0;
for(num = 0;num < n;num++) {
*(a+num) = num+1;//初始化
}
while (out < n-1) {
if (*(p+i) != 0) {
count ++;
}
if (count == m) {//数到了第m个人
count = 0;//将count初始化,重新开始数
printf("%d ",*(p+i));
*(p+i) = 0;//将数到的人赋值为0,不计入循环
out++;
}
i++;
if (i == n) {
i = 0; //从头开始数
}
}
for (num = 0; num < n; num++) {
if (*(a+num) != 0) {
printf("%d\\n",*(a+num));//最后剩下的人
}
}
}
int main()
{
long n;
int m;
long a[50000] = {0};
scanf("%d",&n);
scanf("%d",&m);
left(a,n,m);
return 0;
}
三,算术表达式
题目
任务: 计算算术表达式的值。
算术表达式按中缀给出,以=号结束,包括+,-,/四种运算和(、)分隔符。运算数的范围是非负整数,没有正负符号,小于等于109 。
计算过程中,如果出现除数为0的情况,表达式的结果为”NaN” ; 如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。 输入保证表达式正确。
输入格式:
一行,包括1个算术表达式。算术表达式的长度小于等于1000。
输出格式:
一行,算术表达式的值 。
输入样例:
在这里给出一组输入。例如:
输出样例:
在这里给出相应的输出。例如:
解题思路
- 优先级的比较:建一个函数,如果是‘(’或’)'相应的x标记为0,如果是‘+’,‘-’相应的x标记为1,如果是‘*’,‘/’相应的x标记为2。
int first(char ch) {
int x = 0;
switch (ch) {
case '(':
x = 0; break;
case ')':
x = 0; break;
case '+':
x = 1; break;
case '-':
x = 1; break;
case '*':
x = 2; break;
case '/':
x = 2; break;
}
return x;
}
- 建两个栈,一个存运算符,一个存数字。如果运算符栈的栈顶元素的优先级低于读入运算符的优先级,则将读入运算符进行压栈操作,反之,弹出栈顶元素,调用运算函数,运算结果,然后将运算结果压入数字栈。
- 在数字栈内存入数据时,需进行将char型数据转换成int型数据的操作。这里开辟了一个数组,如果数字是两位以上的数字,则分开存储。最后用atoll函数将string类型的数据转换为int类型。
- 还需注意的一个点是题目要求如果中间结果超出32位有符号整型范围,仍按整型计算,不必特殊处理。但我在课上写的时候没有注意看,使用了long long型栈,导致有一个10分的测试点一直过不去。
- 此代码还有一个问题是如果我只输入一个数字它会输出NaN,试了挺久我也没发现是怎么回事,不影响得分我就没再纠结了,希望有空的大佬能帮我解答一下。
代码
#include<stdio.h>
#include<iostream>
#include<stack>
#include<string>
#include<stdlib.h>
#define maxsize 1001
using namespace std;
stack<char> s1;
stack<int> s2;
int first(char ch);
int yunsuan(int a, int b, char ch);
void result(char str[]);
int first(char ch) {
int x = 0;
switch (ch) {
case '(':
x = 0; break;
case ')':
x = 0; break;
case '+':
x = 1; break;
case '-':
x = 1; break;
case '*':
x = 2; break;
case '/':
x = 2; break;
}
return x;
}
int yunsuan(int a, int b, char ch)
{
int c = 0;
switch (ch)
{
case '+':
c = a + b;
break;
case '-':
c = a - b;
break;
case '*':
c = a * b;
break;
case '/':
if (b == 0)
{
cout << "NaN" << endl;
exit(0);
}
else
c = a / b;
break;
}
return c;
}
void result(char str[])
{
char num[maxsize];
char top1;
int f, c, get1, get2;
int j, i;
for (i = 0; str[i] != '='; i++)
{
switch (str[i])
{
case '(':
s1.push(str[i]);
break;
case '+':
case '-':
case '*':
case '/':
if ((s1.empty()))
s1.push(str[i]);
else if (first(str[i]) > first(s1.top()))
s1.push(str[i]);
else {
while (!s1.empty() && first(str[i]) <= first(s1.top()) && s1.top() != '(')
{
get1 = s2.top();
s2.pop();
get2 = s2.top();
s2.pop();
top1 = s1.top();
c = yunsuan(get2, get1, top1);
s1.pop();
s2.push(c);
}
s1.push(str[i]);
}
break;
case ')':
while (s1.top() != '(')
{
get1 = s2.top();
s2.pop();
get2 = s2.top();
s2.pop();
top1 = s1.top();
s1.pop();
c = yunsuan(get2, get1, top1);
s2.push(c);
}
s1.pop();
break;
default:
j = 0;
do
{
num[j++] = str[i];
i++;
} while (str[i] >= '0' && str[i] <= '9');
num[j] = '\\0';
f = atoll(num);
i--;
s2.push(f);
break;
}
}
while (!s1.empty())
{
get1 = s2.top();
s2.pop();
get2 = s2.top();
s2.pop();
top1 = s1.top();
s1.pop();
c = yunsuan(get2, get1, top1);
s2.push(c);
}
printf("%d", s2.top());
}
int main() {
char str[maxsize];
scanf("%s", str);
result(str);
return 0;
}
四,最喜爱的序列
题目
小唐这段时间在研究序列。拿来N个整数的序列,他给序列中的每个整数都赋予一个喜爱值。喜爱值也是整数,有正有负,越大表明越喜欢。他想知道,如何从序列中连续取最多m个数,他获得喜爱值最大。1≤N≤500000,1≤m≤N。
输入格式:
第一行是两个整数N,m。分别代表序列中数的个数以及能取的最多个数。
第二行用空格隔开的N个整数,第i个整数Li代表他对第i个数的喜爱值。│Li│≤1000
输出格式:
一行,三个数,表示获得最大喜爱值,及第一个取最大喜爱值的区间。
输入样例:
在这里给出一组输入。例如:
输出样例:
在这里给出相应的输出。例如:
解题思路
- 开辟一个数组,读入数据的同时,记录前n项的和,以便后续计算。
for (int i = 1; i <= N; i++) {
cin >> array[i];
array[i] += array[i - 1];//记录前n项的和
}
- 使用STL中的deque双端队列,每读取一个元素就和队尾元素进行比较,如果队非空,且当前元素小于队尾元素,就弹出队尾元素,重复以上操作,直到队空或者队尾元素小于当前元素,如果队首元素的编号不在区间内,则弹出队首元素,重复以上操作。
- 初始化一个变量存储当前区间的元素之和,然后和最大元素之和比较,如果当前区间的元素之和大于最大元素之和,则更新最大元素之和。
代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>
#include<deque>
using namespace std;
deque<int> x;
int main() {
int N, m, front, rear;
cin >> N;
cin >> m;
int array[500001];
array[0] = 0;
for (int i = 1; i <= N; i++) {
cin >> array[i];
array[i] += array[i - 1];//记录前n项的和
}
int sum = 0;
while (!x.empty())
x.pop_back();
x.push_front(0);
for (int i = 1; i <= N; i++) {
while (!x.empty() && array[x.front()] > array[i]) {//判断队列是否为空,弹出大于当前元素的节点的编号
x.pop_front();
}
x.push_front(i);//当前元素的编号入队
while (!x.empty() && i - x.back() > m) {
x.pop_back();
}
int tmp=array[i] - array[x.back()];
if (sum < tmp) {//判断是否更新最大值
sum = tmp;
front = x.back() + 1;
rear = i;
}
}
cout<<sum<<" "<<front<<" "<<rear;
return 0;
}
以上是关于数据结构荣誉课---第一次实验解题报告的主要内容,如果未能解决你的问题,请参考以下文章