龙空技术网

2023年12月23,每天一分钟练习C语言:用抽屉原理找出最大差值

工控小新 70

前言:

此时朋友们对“c语言中23是什么意思”大概比较着重,姐妹们都想要了解一些“c语言中23是什么意思”的相关知识。那么小编也在网络上网罗了一些有关“c语言中23是什么意思””的相关内容,希望我们能喜欢,大家一起来了解一下吧!

学习工控知识,就来工控小新

农历十一月十一日 2023/12/ 24

往期推荐

2023年12月23日,每天花费一分钟练习C语言:用C语言写出杨辉三角的第n行,只需4个步骤!

2023年12月22日,每天花费一分钟练习C语言:十万以内阶乘和数的秘密,只有5个数字知道!

每日一练

/ Daily Exercises

题目:

给定一个无序的数组,找出数组在排序之后,相邻元素之间最大的差值,如果给出数组元素个数小于2,则返回0

题目分析

这个题目的难点在于如何在不实际排序数组的情况下,快速地找出最大的差值。如果我们直接对数组进行排序,那么时间复杂度至少是 ( log⁡)O(nlogn),其中 n是数组的长度。这样的算法可能会超时,或者浪费不必要的时间。

我们可以利用一个数学的性质,即抽屉原理,来简化这个问题。抽屉原理的一个简单的表述是:如果有n+1个苹果放在 n个抽屉里,那么至少有一个抽屉里有两个或以上的苹果。换句话说,如果有多于抽屉数量的物品,那么必然有一个抽屉里有多于一个的物品。

那么,这个性质和我们的题目有什么关系呢?

我们可以把数组的元素看作是苹果,把一些区间看作是抽屉。

具体地,我们先找出数组中的最大值和最小值,然后将它们之间的区间分成 n−1个等长的子区间,每个子区间就是一个抽屉。然后,我们遍历数组,把每个元素放到对应的子区间里,也就是对应的抽屉里。这样,我们就可以得到一个分布情况,有些抽屉里有多个元素,有些抽屉里没有元素,有些抽屉里只有一个元素。

根据抽屉原理,我们可以知道,如果有一个抽屉里没有元素,那么必然有另一个抽屉里有两个或以上的元素。这意味着,如果我们从左到右扫描这些抽屉,那么每当我们遇到一个空抽屉,我们就可以确定,这个空抽屉的左边的抽屉里有元素,而且这个元素是这个抽屉里的最大值;这个空抽屉的右边的抽屉里也有元素,而且这个元素是这个抽屉里的最小值。那么,这两个元素之间的差值,就是一个候选的最大差值。我们只需要记录下这些候选的最大差值,然后从中选出最大的一个,就是我们要求的答案。

这个算法的时间复杂度是 O(n),因为我们只需要遍历一次数组,然后扫描一次抽屉。空间复杂度也是 O(n),因为我们需要存储每个抽屉的最大值和最小值。

程序展示

根据上面的分析,我们可以用C语言来实现这个算法。我们首先定义一个结构体,用来表示每个抽屉的信息,包括是否有元素,最大值和最小值。然后,我们定义一个函数,用来计算给定数组的最大差值。函数的主要步骤如下:

1、初始化一个长度为n−1的结构体数组,用来表示n−1个抽屉,每个抽屉的信息都设为初始值,即没有元素,最大值和最小值都为0。2、遍历数组,找出最大值和最小值,以及每个元素对应的抽屉的下标。把每个元素放到对应的抽屉里,更新抽屉的信息,即是否有元素,最大值和最小值。3、扫描抽屉,记录下每个空抽屉的左右两边的元素的差值,作为候选的最大差值。从中选出最大的一个,作为最终的答案。4、如果数组的长度小于2,或者最大值和最小值相等,那么返回0,表示没有差值。

#include <stdio.h>#include <stdlib.h>#include <time.h>// 定义一个结构体,用来表示每个抽屉的信息typedef struct bucket {    int has_element; // 是否有元素    int max; // 最大值    int min; // 最小值} bucket;// 定义一个函数,用来比较两个整数的大小,用于排序int compare(const void* a, const void* b) {    return *(int*)a - *(int*)b;}// 定义一个函数,用来生成一个长度为n的随机数组,返回数组的指针int* generate_random_array(int n) {    int* arr = (int*)malloc(sizeof(int) * n); // 分配内存空间    for (int i = 0; i < n; i++)   {        arr[i] = rand() % 100; // 生成0到99之间的随机整数    }    return arr;}// 定义一个函数,用来打印一个数组,方便查看void print_array(int* arr, int n) {    printf("[");    for (int i = 0; i < n; i++)   {        printf("%d", arr[i]);        if (i < n - 1) printf(", ");    }    printf("]\n");}// 定义一个函数,用来计算给定数组的最大差值int max_gap(int* arr, int n) {    // 如果数组的长度小于2,或者数组中的元素都相等,那么返回0    if (n < 2) return 0;    int max = arr[0], min = arr[0];    for (int i = 1; i < n; i++)   {        if (arr[i] > max) max = arr[i];        if (arr[i] < min) min = arr[i];    }    if (max == min) return 0;    // 初始化一个长度为n-1的结构体数组,用来表示n-1个抽屉    bucket* buckets = (bucket*)malloc(sizeof(bucket) * (n - 1));    for (int j = 0; j < n - 1; j++)   {        buckets[j].has_element = 0;        buckets[j].max = 0;        buckets[j].min = 0;    }    // 遍历数组,找出每个元素对应的抽屉的下标,把元素放到对应的抽屉里,更新抽屉的信息    int gap = max - min; // 数组的最大值和最小值的差值    int bucket_size = gap / (n - 1); // 每个抽屉的大小    if (bucket_size == 0) bucket_size = 1; // 防止除数为0的情况    for (int k = 0; k < n; k++)   {        int index = (arr[k] - min) / bucket_size; // 计算元素对应的抽屉的下标        if (index >= n - 1) index = n - 2; // 防止下标越界的情况        if (buckets[index].has_element == 0)     { // 如果抽屉里没有元素,那么把元素设为最大值和最小值            buckets[index].has_element = 1;            buckets[index].max = arr[k];            buckets[index].min = arr[k];        }     else     { // 如果抽屉里有元素,那么更新最大值和最小值            if (arr[k] > buckets[index].max) buckets[index].max = arr[k];            if (arr[k] < buckets[index].min) buckets[index].min = arr[k];        }    }    // 扫描抽屉,记录下每个空抽屉的左右两边的元素的差值,作为候选的最大差值    int max_gap = 0; // 最大差值    int prev = min; // 前一个非空抽屉的最大值,初始为数组的最小值    for (int m = 0; m < n - 1; m++)   {        if (buckets[m].has_element == 0) continue; // 如果抽屉为空,跳过        int curr = buckets[m].min; // 当前非空抽屉的最小值        int curr_gap = curr - prev; // 当前差值        if (curr_gap > max_gap) max_gap = curr_gap; // 更新最大差值        prev = buckets[m].max; // 更新前一个非空抽屉的最大值  }  // 释放内存空间  free(buckets);  // 返回最大差值  return max_gap;}// 定义一个函数,用来测试我们的函数是否正确void test(int n) {    // 生成一个长度为n的随机数组    int* arr = generate_random_array(n);    // 打印数组    printf("The original array is: ");    print_array(arr, n);    // 对数组进行排序    qsort(arr, n, sizeof(int), compare);    // 打印排序后的数组    printf("The sorted array is: ");    print_array(arr, n);    // 计算相邻元素之间的最大差值,作为期望的答案    int expected = 0;    for (int i = 1; i < n; i++)   {        int curr = arr[i] - arr[i - 1];        if (curr > expected) expected = curr;    }    // 调用我们的函数,计算数组的最大差值,作为实际的答案    int actual = max_gap(arr, n);    // 比较期望的答案和实际的答案是否相等    printf("The expected answer is: %d\n", expected);    printf("The actual answer is: %d\n", actual);    if (expected == actual)   {        printf("Correct!\n");    }   else   {        printf("Wrong!\n");    }    // 释放内存空间    free(arr);}// 定义主函数,用来运行测试int main() {    // 设置随机数种子    srand(time(NULL));    // 测试10次    for (int i = 0; i < 10; i++)   {        printf("Test %d:\n", i + 1);        // 随机生成一个长度为1到10之间的正整数        int n = rand() % 10 + 1;        // 调用测试函数        test(n);        printf("\n");    }    return 0;}

程序测试

为了验证我们的程序是否正确,我们可以用一些测试用例来检验。我们可以用以下的方法来生成测试用例:

随机生成一个长度为n的数组,其中n是一个随机的正整数,数组的元素是随机的整数。对数组进行排序,然后计算相邻元素之间的最大差值,作为期望的答案。调用我们的函数,计算数组的最大差值,作为实际的答案。比较期望的答案和实际的答案是否相等,如果相等,说明我们的函数正确,如果不相等,说明我们的函数有误。

源代码获取

#软件下载通道#

我用夸克网盘分享了「20231224」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。

链接:

(链接和提取码建议复制粘贴,手动输入容易出现错误)

#支持一下#

分享整理,测试发布不易 如果您方便的话可以帮忙点一下↓↓

谢谢大家!

下期题目

重复的DNA序列

所有DNA都由一系列缩写为A',C,G'和·T的核昔酸组成,例如:ACGAATTCCG"。在研究DNA 时,识别DNA中的重复序列有时会对研究非常有帮助。编写一个函数来找出所有目标子串,目标子串的长度为10,且在 DNA 字符串s 中出现次数超过一次。

点赞加关注,学习不迷路

微信公众号|工控小新

学习工控知识就来工控小新,为你提供工控笔记知识:EPLAN电气绘图 | TIA博图基础 | CAD | C语言教学 | 单片机基础 | 三菱PLC ... 每日持续更新中

#头条创作挑战赛#

标签: #c语言中23是什么意思 #c语言求3个数的最大值函数是多少 #c 字符串比较大小 #c语言求最小值及其最大下标