吉林大学软件工程数据结构第一次上机

呜呜呜,本来是想进入荣誉课学习更好的知识,没想到这么难,但作为一个编程小白,也希望让自己的能力更强。。。

本文部分代码和思想借鉴于网络大佬。

7-1 数列查询

分数 100

全屏浏览题目

切换布局

作者 谷方明

单位 吉林大学

已知数列的通项公式为:

     f(n) = f(n-1)*11/10,f[1]=10.

通项从左向右计算,*和/分别表示整数乘法和除法。

现在,要多次查询数列项的值。

输入格式:

第1行,1个整数q,表示查询的次数, 1≤q≤10000.

第2至q+1行,每行1个整数i,表示要查询f(i)的值。

输出格式:

q行,每行1个整数,表示f(i)的值。查询的值都在32位整数范围内。

输入样例:

在这里给出一组输入。例如:

3

1

2

3

输出样例:

在这里给出相应的输出。例如:

10

11

12

代码长度限制

16 KB

时间限制

10 ms

内存限制

1 MB

这题比较简单,作为没有数据结构和算法基础的小白,我先想的是能用数组解决,绝不用递归(时间限制),因为假期看了一些排序方面的知识,我私以为桶排序的思想是最简单的(个人想法,可能不对),就是把一些输入的东西用另一个数组存起来就好了,方便后面的进行,上代码:

#include<stdio.h>

long long a[10001];

int b[10001];

int main() {

a[1]=10;

for(int i=2; i<=10001; i++) {

a[i]=a[i-1]*11/10;

}

int n; scanf("%d",&n);

for(int i=1; i<=n; i++) {

scanf("%d",&b[i]);

}

for(int i=1; i<=n; i++) {

printf("%lld\n",a[b[i]]);

}

return 0;

}

时间复杂度:O(n).

空间复杂度:O(n).

7-2 报数游戏

分数 100

全屏浏览题目

切换布局

作者 谷方明

单位 吉林大学

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

输入格式:

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

输出格式:

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

输入样例:

在这里给出一组输入。例如:

5 2

输出样例:

在这里给出相应的输出。例如:

2 4 1 5 3

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

  1. 这题我看课里的大佬讲这是约瑟夫问题(后面探讨),同样因为实力实在有限,不知道咋做,于是我就又用多个数组开始硬解(实力不够,无奈。。。)

用一个数组来存放 1,2,3 ... n 这 n 个编号,如图(这里我们假设n = 6, m = 3)

 然后不停着遍历数组,对于被选中的编号,我们就做一个标记,例如编号 arr[2] = 3 被选中了,那么我们可以做一个标记,例如让 arr[2] = -1,来表示 arr[2] 存放的编号已经出局的了。

然后就按照这种方法,不停着遍历数组,不停着做标记,直到数组中只有一个元素是非 -1 的,这样,剩下的那个元素就是我们要找的元素了。借鉴一下网图,这是后来复盘后,网络大佬其中的一个方法,

但我是没有将数组的序号更新,而是另设了一个标志数组来储存。(思想差不多)。

上代码:

#include<stdio.h>

int a[50001];

int b[50001];

int c[50001];

int main(){

int n,m;

scanf("%d%d",&n,&m);

for(int i=1; i<=n; i++){

a[i]=i;

}

int top=0;

int j=1;

for(int i=1; i<=n;) {

if(c[i]==1) {

} else {

top++;

}

if(top==m) {//top到达数值则更新

top=0;

b[j]=a[i];

c[i]=1;//标志数组

j++;

}

if(i==n) {

i=0;//循环

}

i++;

if(j==n+1)break;//容易卡人,真是要判断好临界条件。

}

for(int i=1; i<=n; i++) {

if(i==n)printf("%d",b[i]);

else {

printf("%d ",b[i]);

}

}

return 0;

}

约瑟夫问题:有 N 个人围成一圈,每个人都有一个编号,编号由入圈的顺序决定,第一个入圈的人编号为 1,最后一个为 N,从第 k (1<=k<=N)个人开始报数,数到 m (1<=m<=N)的人将出圈,然后下一个人继续从 1 开始报数,直至所有人全部出圈,求依次出圈的编号。

暂介绍三种方法(实力有限):

  1. 数组。
  2. 环形链表:用链表来处理其实和上面处理的思路差不多,只是用链表来处理的时候,对于被选中的编号,不再是做标记,而是直接移除,因为从链表移除一个元素的时间复杂度很低,为 O(1)。当然,上面数组的方法你也可以采用移除的方式,不过数组移除的时间复杂度为 O(n)认为此种思想更好的解决另一种看到的约瑟夫问题:约瑟夫(Joseph)问题的一种描述是:编号为1,2,...,+n的n个,个人按顺时针方向围坐一圈,+每人持有一个密码(正整数)。一开始选任一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将它的密码(链表就可以储存密码了)作为新的m值。
  3. 递归:(这不建议真的用,毕竟一涉及递归时间就容易出问题,但它真的是普适性强)old = (new + m - 1) % n + 1网络大佬们是真的强,一行就解决递归出口就是n=1.

3.7-3 算术表达式计算

分数 100

全屏浏览题目

切换布局

作者 谷方明

单位 吉林大学

任务: 计算算术表达式的值。

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

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

输入保证表达式正确。

输入格式:

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

输出格式:

一行,算术表达式的值 。

输入样例:

在这里给出一组输入。例如:

(1+30)/3=

输出样例:

在这里给出相应的输出。例如:

10

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

这题说实话我看到的时候直接跳了,因为我知道自己写不出来,就是平时理论没有付诸实践,到不得不用数据结构的时候就懵了。

两个栈分别存数字字符和符号字符,算法就是老师上课讲的,主要是一动手就不知道咋干了。

上代码:

#include<iostream>

#include<stack>

#include<algorithm>

#include<stdlib.h>

#include<string.h>

using namespace std;

int main(){

std::stack<int>p;        //数值栈

std::stack<char>q;       //符号栈

int i,j=0,k=0,l,sum1,sum2;

char s[1010],m;

scanf("%s",s);

l=strlen(s);

for(i=0;i<l;i++){

if(s[i]>='0'&&s[i]<='9'){

j=j*10+s[i]-'0';

k=1;               //做标志来判断后续的是否还为数字

}

else{

if(k){

p.push(j);

k=0;j=0;

}

if(q.empty())

{q.push(s[i]);       //压入符号

continue ;

}

m=q.top();

switch(s[i]){

case '+':

case '-':if(m=='+'||m=='-'||m=='*'||m=='/'){         //如果压入+或-则将前边的优先级低的计算

sum2=p.top();p.pop();sum1=p.top();p.pop();

if(m=='+')

p.push(sum1+sum2);

if(m=='-')

p.push(sum1-sum2);

if(m=='/')

{

if(sum2==0)

{printf("NaN");

exit(0);}

p.push(sum1/sum2);

}

if(m=='*')

p.push(sum1*sum2);

q.pop();

}

q.push(s[i]);break;

case '*':

case '/':if(m=='*'||m=='/'){

sum2=p.top();p.pop();sum1=p.top();p.pop();

if(m=='/')

{

if(sum2==0)

{printf("NaN");

exit(0);}

p.push(sum1/sum2);

}

if(m=='*')

p.push(sum1*sum2);

q.pop();

}

q.push(s[i]);break;

case '(':q.push(s[i]);break;//左括号则将其视为一个新的表达式重新计算

case ')':while(q.top()!='('){//右括号则将标志着这个表达式计算完毕弹栈直到遇到左括号

m=q.top();

if(m=='+'||m=='-'||m=='*'||m=='/'){

sum2=p.top();p.pop();sum1=p.top();p.pop();

if(m=='+')

p.push(sum1+sum2);

if(m=='-')

p.push(sum1-sum2);

if(m=='/')

{

if(sum2==0)

{printf("NaN");

exit(0);}

p.push(sum1/sum2);

}

if(m=='*')

p.push(sum1*sum2);

q.pop();

}

} q.pop();break;

}

}

}

  while(!q.empty()){//将剩余的数值和符号计算完毕

   m=q.top();

if(m=='+'||m=='-'||m=='*'||m=='/'){

sum2=p.top();p.pop();sum1=p.top();p.pop();

if(m=='+')

p.push(sum1+sum2);

if(m=='-')

p.push(sum1-sum2);

if(m=='/')

{

if(sum2==0)

{printf("NaN");

exit(0);}

p.push(sum1/sum2);

}

if(m=='*')

p.push(sum1*sum2);

q.pop();

}

  }

  printf("%d",p.top());

  return 0;

}

时间复杂度(O(n));

空间复杂度(O(n));

7-4 最喜爱的序列

分数 100

全屏浏览题目

切换布局

作者 谷方明

单位 吉林大学

 小唐这段时间在研究序列。拿来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

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

这题我看的时候感觉有点小稳,因为老师之前发的练习题我不会,去问唐班大佬,了解到了前缀和,但编程小白的不足在这道题还是显得淋漓尽致,不会单调队列。。。我一开始没好好读题,以为是只拿m个,写的很自信,但有一个点死活不过,但后来发现的时候已经下课了。。。

还有我这个算法小白真的要好好学习c++的STL,各种算法太方便了太快了。

上代码(在网上搜集到比较简便的算法):

#include<iostream>

#include<queue>

#include<algorithm>

using namespace std;

int a[500010];

int main() {

std::deque<int>q;//还是要好好学习STL

int m, n,i,j,k,l,l0,r,max=0xffffffff;//max设置为一个最小值为负值

scanf("%d%d", &n, &m);

q.push_back(0);//先押入一个0注意我们压入的是前缀和数组的下标0代表的是下标由于a[0]=0;所以我们压入这个数字并不会对结果造成影响。

for (i = 1;i <= n;i++)

{

scanf("%d", &a[i]);

a[i] += a[i - 1];    //将起转换为前缀和

k = a[i] - a[q.front()]; //计算这段区间内的最大值

if (k > max) {

l0 = q.front();r = i;max = k;

}

while (!q.empty()) {//对区间进行维护

l = q.back();

if (i - q.front() == m)

{

q.pop_front(); continue;

}

if (a[l] > a[i])

q.pop_back();

else

break;

}

q.push_back(i);

}

printf("%d %d %d", max, l0+1, r);

}

时间复杂度:O(n);(另一种方法再为m遍历建立一个数组发现爆了,n方好像就不行了)。

空间复杂度:O(n).

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值