电子科技大学链时代工作室招新题C语言部分---题号D

1. 题目

这道题大概的意思就是对一个整形数组的元素进行排序,然后按新的顺序打印原本的下标;

例如,在题目给出的Note部分,{a1, a2, a3, a4, a5}进行排序之后变为了{a2, a1, a4, a3, a5},于是输出2 1 4 3 5。

排序的规则是,排完序之后,使得新数组与原数组的每个对应位置上的元素相加之后,的到一个相同的数;

例如,在题目给出的Note部分,a1 + a2 = 6,a2 + a3 = 6,……

输入

第一行输入数组的元素个数,第二行输入数组的内容

输出

依次输出新数组的原下标,如果无法找到这样一个新的排列顺序,就输出-1。


2. 第一版解法

第一版是暴力解法,直接对题意进行翻译,结果也是不出意外地超时了。

2.1 思路

1. 首先假设第一个元素与第i个元素配对,并将它们的和存在一个变量sum中。

2. 然后依次检查之后的元素是否能找到另一个元素与其相加,得到的和恰好等于sum。

3. 如果某个元素找不到与其相对应的元素,就使第一个元素与i+1个元素配对,并重新检查。

4. 若检查到最后,每一个元素都无法和第一个元素配对,则表示无法找到符合题意的排序,打印-1并退出。

5. 如果第一个元素与某个元素配对时,每一个元素都能找到与自己相配对的元素,则按顺序打印与原数组相配对的元素的下标。

2.2 代码

#include <stdio.h>
#include <stdlib.h>void sort(int n, int arr[])
{int i = 0;for(i = 0; i < n; i++)//arr[0]和arr[i]对应{int x = 1;int* ret = (int*)malloc(sizeof(int) * n);int* test = (int*)malloc(sizeof(int) * n);for(int h = 0; h < n; h++){test[h] = 1;}ret[0] = i;test[i] = 0;int tmp = arr[0] + arr[i];int j = 1;for(j = 1; j < n; j++)//后面元素找对应{int flag = 1;for(int k = 0; k < n; k++){if((tmp == arr[j] + arr[k])&&test[k] != 0)//找到对应元素{flag = 0;test[k] = 0;ret[x] = k;x++;break;}}if(flag)//某号元素找不到对应break;}if(j == n)//找全了{for(int y = 0; y < n; y++){printf("%d ", ret[y]+1);}break;}free(ret);free(test);}if(i == n)printf("-1\n");
}int main()
{int n = 0, k = 0;k = scanf("%d", &n);int* arr = (int*)malloc(sizeof(int) * n);for(int i = 0; i < n; i++){k = scanf("%d", &arr[i]);}sort(n, arr);free(arr);return 0;
}

2.3 总结

这一版解法缺乏对题目的深入分析,以及对数学关系的挖掘。

由此导致程序做了很多不必要的计算,使得时间复杂度过高而超时。


3. 第二版解法

这一版尝试减小时间复杂度。

3.1 挖掘数学关系,优化算法

3.1.1 有关sum

1. sum是每组元素相加之和,我们仔细分析就会发现,sum其实是平均数的二倍,于是我们无需再尝试第一个元素该与谁配对。

2. 其次,sum是两个整形之和,它也必定为整数,所以我们将sum定义为浮点数,并检验“sum == (int)sum”是否成立,如果不成立则直接输出-1。这样,某些不能找到结果的样例就可以直接判断为不符合要求,而不需要找到最后再做出判断;

例如数组{1, 2, 3, 7},其平均数的二倍为6.5,一定不能找到合适的结果。

3.1.2 有关配对

如果第1号元素与第5号元素配对了,那么我们就不必再去寻找第5号元素该与第几号元素配对,直接使其与1号元素配对即可;

例如题上第一个案例{4, 2, 5, 1, 3},打印的结果为2 1 4 3 5

结果的第一个位置上是2,第二个位置上是1

           第三个位置上是4,第四个位置上是3

           第五个位置上是5。

这样就可以为我们的循环减少一半的工作量。

3.2 代码

#include <stdio.h>
#include <stdlib.h>void solve(int n, int arr[])
{double sum = 0;for(int j = 0; j < n; j++){sum += (double)arr[j];}sum = sum*2/n;if(sum == (int)sum){int i = 0;int ret[n];for(int j = 0; j < n; j++){ret[j] = 0;}for(i = 0; i < n; i++){if(ret[i] != 0)continue;int flag = 1;for(int j = 0; j < n; j++){if(ret[j] != 0)continue;if(arr[i] + arr[j] == sum){flag = 0;ret[i] = j + 1;ret[j] = i + 1;break;}}if(flag){printf("%d\n", -1);return;}}if(i == n)for(int k = 0; k < n; k++)printf("%d ", ret[k]);printf("\n");}elseprintf("%d\n", -1);
}int main()
{int n = 0, k = 0;k = scanf("%d", &n);int* arr = (int*)malloc(sizeof(int) * n);for(int i = 0; i < n; i++){k = scanf("%d", &arr[i]);}solve(n, arr);free(arr);return 0;
}

3.3 总结

这次深入分析了题目中的数学关系,并对算法做了大量的优化。

但是仍然超时,能反应的过来吗牢底?我当时血压都高了。

但是没办法,我们只能继续做优化。


4. 最终版本

算法已经够简单了,优化一下思路。

4.1 换个思路

就刚才的思路而言,我们必须要用到二重循环,尽管我们已经将二重循环的工作量减少了一半,但仍然超时。那么就说明,一定有更好的算法,使得时间复杂度能降到O(n)

4.1.1 排序的思路

经过上一版的启发,我们发现,最大的数一定和最小的数配对,第二小的数一定和第二大的数配对……

于是,我们想到先将数组进行排序,这样就不必再费力再用二重循环去找配对的元素了。

可是,有两个问题(这也是我一开始没有采用这种思路的原因):

1. 排序的实现,仍然需要二重循环(博主比较菜,还只会冒泡排序)。

2. 排序之后如何知道每个元素原来的下标。

对于第一个问题,我们可以只用qsort函数来帮助我们实现排序,因为其采用的是一种快速排序的方法。

对于第二个问题:

1. 我一开始的想法是将原数组的数据存储到一个结构体数组中,结构体包含两个元素,一个是int类型的数据,一个是该数据对应的下标。让qsort函数按照数据排序,我再访问另一个成员对下标进行配对。

2. 但是,数据本来就是由两部分构成的啊:数据的值与地址。所以我可以将各个元素的地址存放到一个指针数组中,然后让qsort根据其指向的值对地址进行排序,又由地址减去arr的到下标,进行配对。

4.2 代码

#include <stdio.h>
#include <stdlib.h>int add_cmp(const void* e1, const void* e2)
{return **(int**)e1 - **(int**)e2;
}void solve(int n, int arr[])
{double sum = 0;for(int j = 0; j < n; j++){sum += (double)arr[j];}sum = sum*2/n;if(sum == (int)sum){int** add = (int**)malloc(sizeof(int*) * n);int* ret = (int*)malloc(sizeof(int) * n);for(int i = 0; i < n; i++){add[i] = &arr[i];}qsort(add, n, sizeof(int*), add_cmp);for(int i = 0, j = n-1; i <= j; i++, j--){if(*add[i] + *add[j] != sum){printf("%d\n", -1);return;}else{int e1 = add[i] - arr;int e2 = add[j] - arr;ret[e1] = e2 + 1;ret[e2] = e1 + 1;}}for(int i = 0; i < n; i++){printf("%d ", ret[i]);}printf("\n");free(add);free(ret);}elseprintf("%d\n", -1);
}int main()
{int n = 0, k = 0;k = scanf("%d", &n);int* arr = (int*)malloc(sizeof(int) * n);for(int i = 0; i < n; i++){k = scanf("%d", &arr[i]);}solve(n, arr);free(arr);return 0;
}

4.3 总结

这次循环最多只有一重了,如果再不过就不太厚道了。那么也是理所当然地拿下第一题。

你问为什么第一题是D?因为前三道是保护自尊心的送分题,小学生都会做,我们就直接跳过。

C语言题的题号一直到H,感兴趣的同学点波关注,我们尽快更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/539580.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机视觉】二、图像形成:1、向量和矩阵的基本运算:线性变换与齐次坐标

文章目录 一、向量和矩阵的基本运算1、简单变换1. 平移变换2. 缩放变换3. 旋转变换4. 一般线性变换 2、齐次坐标0. 齐次坐标表示1. 2D点的齐次坐标变换2. 投影空间 ( x , y , w ) (x, y, w) (x,y,w)3. 2D直线的齐次坐标表示a. 直线的参数方程表示b. 直线的法向量和原点距离表示…

在Linux/Ubuntu/Debian中使用7z压缩和解压文件

要在 Ubuntu 上使用 7-Zip 创建 7z 存档文件&#xff0c;你可以使用“7z”命令行工具。 操作方法如下&#xff1a; 安装 p7zip&#xff1a; 如果你尚未在 Ubuntu 系统上安装 p7zip&#xff08;7-Zip 的命令行版本&#xff09;&#xff0c;你可以使用以下命令安装它&#xff1a;…

SVN修改已提交版本的注释

目录 一、需求分析 二、问题分析 三、解决办法 一、需求分析 ​开发过程中&#xff0c;在SVN提交文件后&#xff0c;发现注释写的不完整或不够明确&#xff0c;想再修改之前的注释文字​。 使用环境&#xff1a; SVN服务器操作系统&#xff1a;Ubuntu 20.04.6 LTS SVN版本&…

串口协议、I2C协议、SPI协议总结

目录 一、串口协议 1.串口基本认知 2.RS-232 3.RS-422 4.RS-485 &#xff08;1&#xff09;RS232电平&#xff1a; &#xff08;2&#xff09;TTL电平&#xff1a; 6.串口51开发板实现 &#xff08;1&#xff09;软件自动配置&#xff1a; &#xff08;2&#xff09;…

React——react 的基本使用

前提&#xff1a;安装全局的脚手架&#xff0c;通过create-creat-app 项目名&#xff0c;我们创建好一个新项目&#xff0c;cd进去&#xff0c;通过npm start去运行该项目 注意&#xff1a;简单看下demo的配置&#xff0c;在根目录我们可以看到&#xff0c;没有任何webpack的…

windows 安装 gitlab-runner CICD

点击搜索图标 手动输入PowerShell, 右键点击管理员权限打开&#xff0c; 一、安装 安装 gitlab runner 文档参考地址 1、下载exe执行文件 我这里是 win64 https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe 2、创建 gitla…

基于Java的海南旅游景点推荐系统(Vue.js+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户端2.2 管理员端 三、系统展示四、核心代码4.1 随机景点推荐4.2 景点评价4.3 协同推荐算法4.4 网站登录4.5 查询景点美食 五、免责说明 一、摘要 1.1 项目介绍 基于VueSpringBootMySQL的海南旅游推荐系统&#xff…

大话设计模式——6.工厂方法模式(Factory Method Pattern)

1.介绍 工厂方法模式也称工厂模式&#xff0c;是简单工厂模式的进一步抽象。定义一个用于创建对象的接口&#xff0c;使一个类的实例化延迟到其子类&#xff0c;让子类决定实例化哪个类。通过工厂父类定义负责创建产品的公共接口&#xff0c;通过子类确定所需要创建的类型。 属…

Spring, SpringBoot, SpringCloud,微服务

1,SSM (Spring+SpringMVC+MyBatis) SSM框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容),常作为数据源较简单的web项目的框架。 Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet,Controlle…

力扣日记3.14-【贪心算法篇】376. 摆动序列

力扣日记&#xff1a;【贪心算法篇】376. 摆动序列 日期&#xff1a;2024.3.14 参考&#xff1a;代码随想录、力扣 376. 摆动序列 题目描述 难度&#xff1a;中等 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;…

【matlab】如何将.mat文件与.nii文件互转

【matlab】如何将.mat文件与.nii文件互转 .mat转为.nii文件 有时候代码需要读取的是.nii文件&#xff0c;但是如何现有的数据是.mat格式&#xff0c;需要将.mata转化为.nii文件 1、先加载.mat文件 % 加载.mat文件 load(your_mat_file.mat); % 请将your_mat_file.mat替换为实…

微软远程桌面RD Client:连接与管理的新境界

微软远程桌面RD Client&#xff1a;连接与管理的新境界 在数字化日益深入的今天&#xff0c;远程工作与管理已成为许多企业和个人的首选。微软远程桌面RD Client作为一款功能强大的远程连接工具&#xff0c;凭借其出色的性能和便捷的操作&#xff0c;受到了广泛的关注和好评。…