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

news2024/12/23 13:41:24

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");
    }
    else
    printf("%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);
    }
    else
    printf("%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.coloradmin.cn/o/1525361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaScript编程实操07】1.查找一个字符串中是否具有某个字符 2.完成数组去重

前言 1、查找一个字符串中是否具有某个字符 代码&#xff1a; 实现效果&#xff1a; 2、完成数组去重 第一种方法 代码&#xff1a; 实现效果&#xff1a; 第二种方法 代码&#xff1a; 实现效果&#xff1a; 总结 前言 本次主要是针对Javascript阶段的字符串和数组…

Python图像处理:3.七种图像分割方法

一、常见图像分割方法 (1)传统算法 阈值分割&#xff08;Thresholding&#xff09;&#xff1a;这是最简单也是应用最广泛的一种分割方法&#xff0c;通过选定一个阈值将图像转换为二值图像&#xff0c;从而分割出目标区域。这种方法适用于图像的前景和背景对比明显的情况。 …

链表中的倒数第k个结点 合并两个链表 分割链表 链表的回文结构

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:分析力扣中有关链表的部分题目. 目录 前言一、链表中倒…

【冲击蓝桥篇】动态规划(下):你还在怕动态规划!?进来!答题模板+思路解析+真题实战

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

Java项目:60 ssm基于JSP的乡镇自来水收费系统+jsp

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统可以提供信息显示和相应服务&#xff0c; 其管理员管理水表&#xff0c;审核用户更换水表的请求&#xff0c;管理用户水费&#xff0c;包括抄表以…

运动想象 (MI) 迁移学习系列 (9) : 数据对齐(EA)

运动想象迁移学习系列:数据对齐&#xff08;EA&#xff09; 0. 引言1. 迁移学习算法流程2. 欧式对齐算法流程3. 与RA算法进行对比4. 实验结果对比5. 总结欢迎来稿 论文地址&#xff1a;https://ieeexplore.ieee.org/abstract/document/8701679 论文题目&#xff1a;Transfer Le…

【Spring Cloud】Sentinel限流

控制台下载https://github.com/alibaba/Sentinel/releases # 控制台启动 java -Dserver.port10888 -Dcsp.sentinel.dashboard.serverlocalhost:10888 -Dproject.namesentinel-dashboard -jar sentinel-dashboard.jar引入依赖 <dependency><groupId>com.alibaba.c…

hadoop分布式环境ssh设置免密登陆之后目标主机更换无法连接解决

在进行hadoop分布式环境搭建时&#xff08;三台机&#xff0c;master&#xff0c;slave1&#xff0c;slave2&#xff09;&#xff0c;后期slave2系统出现问题&#xff0c;更换新机后&#xff0c;master与slave2文件传输失败&#xff1a; 以为是秘钥过期的问题&#xff0c;更换…

微信小程序调用百度智能云API(菜品识别)

一、注册后生成应用列表创建应用 二、找到当前所需使用的api菜品识别文档 三、点链接看实例代码 这里需要使用到如下几个参数&#xff08;如下&#xff09;&#xff0c;其他的参数可以不管 client_id &#xff1a; 就是创建应用后的API Keyclient_secret&#xff1a; 就是创建…

连续八年在3·15发布新酿造年份国标酒,国台真实年份印记深入人心

对许多酱酒爱好者来说&#xff0c;每年的315已经成为与国台的年度约定日。 自2017年开始&#xff0c;国台都会在这个特殊的日子发布新酿造年份的国台国标酒&#xff0c;至今已连续8年。回首往届盛会依旧历历在目&#xff0c;这一天已然成为国台与所有国粉的约定日&#xff0c;…

【K8S】docker和K8S(kubernetes)理解?docker是什么?K8S架构、Master节点 Node节点 K8S架构图

docker和K8S理解 一、docker的问世虚拟机是什么&#xff1f;Docker的问世&#xff1f;docker优点及理解 二、Kubernetes-K8SK8S是什么&#xff1f;简单了解K8S架构Master节点Node节点K8S架构图 一、docker的问世 在LXC(Linux container)Linux容器虚拟技术出现之前&#xff0c;业…

Anaconda几个优势

目录 简介优势一、虚拟环境&#xff0c;方便配置版本二、版本清晰可见三、快速打开虚拟环境下的jupyter 简介 Anaconda是一个流行的开源Python和R编程语言的发行版&#xff0c;用于科学计算、数据科学和机器学习任务。它包含许多常用于这些领域的包和库&#xff0c;如NumPy、Sc…

电脑高温怎么办?教你几招,迅速降温!

电脑在长时间运行或者负载较高时&#xff0c;容易出现高温问题&#xff0c;这不仅会影响电脑的性能和稳定性&#xff0c;还可能导致硬件损坏。因此&#xff0c;了解如何解决电脑高温问题是至关重要的。在本文中&#xff0c;我们将介绍三种常见的方法&#xff0c;以分步骤详细说…

前端项目部署后,如何提示用户版本更新

目录 前言解决方案1、public目录下新建manifest.json2、写入当前时间戳到manifest.json3、检查版本更新4、woker线程5、入口文件引入 可能出现的问题 前言 项目部署上线后&#xff0c;特别是网页项目&#xff0c;提示正在操作系统的用户去更新版本非常 important。一般我们都会…

深度学习 精选笔记(12)卷积神经网络-理论基础1

学习参考&#xff1a; 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增)&#xff0c;以达到集多方教程的精华于一文的目的。 ③非常推荐上面&#xff08;学习参考&#x…

C语言学习笔记day8

一维数组冒泡排序法 1. 作用 将乱序的一维数组按照从小到大的顺序排列 2. 原理示意图 3. 代码 #include <stdio.h> #include <stdlib.h> #include <time.h>int main(void) {int a[5] {0};int len sizeof(a) / sizeof(a[0]);int i 0;int j 0;int tmp …

【每日算法】理论:常见AIGC模型; 刷题:力扣单调栈

上期文章 【每日算法】理论&#xff1a;生成模型基础&#xff1b; 刷题&#xff1a;力扣单调栈 文章目录 上期文章一、上期问题二、理论问题1、stable diffusion模型的网络架构2、T5的网络架构&#xff08;Text-To-Text Transfer Transformer模型&#xff09;3、SDXL模型4、DA…

打靶记录(个人学习笔记)

一、信息收集 1、主机发现 通过nmap对此网段进行扫描&#xff0c;可以确定靶机ip为192.168.189.144 2、端口扫描 确定了靶机ip之后&#xff0c;我们来扫描端口 发现80端口开放&#xff0c;先访问80端口 用插件识别出一些信息 Wappalyzer插件获得信息&#xff1a;Web服务&am…

服务器开机不输入密码自动进系统, 与设置开机启动项

打开运行[win R ] 输入&#xff1a; control Userpasswords2设置开机启动项 运行 输入 shell:startup在这里插入图片描述

Java自定义注解实现参数校验

1、 定义注解内 自定义如下&#xff0c;本例子以校验手机号码为例 需要校验手机号码标上此注解即可。 其中Mobilelidator 类则是实现自定义校验ConstraintValidator类的接口实现类 2、ConstraintValidator 定义接口实现 ConstraintValidator 自定义接口实现如下图