基数排序及利用数组简化解题

news2024/12/24 9:18:20

红豆不堪看,满眼相思泪

在这里插入图片描述

 本文主要是帮助大家熟练掌握利用数组进行有关判断的题目,看完本文后在之后的刷题中都可以利用这种思想,当然举例中的题目利用该种方法可能不是最优解,但绝对是你看到题目不用思考太多就可以做出来的方法,当然我也会介绍所列题目的其他方法以供大家思考,话不多说,进入正题。

基数排序
思想:已经给定一个数组,数组中就是我们需要排序的数列,再开辟一个数组,该数组的个数n为要排序的数中最大的数+1且全部初始化为0,根据需要排序数组中的数,找到新开辟的数组中该数的下标的位置,将该位置的数++。
例如
在这里插入图片描述
 逻辑很简单,直接谈如何优化,一眼看出,某种情况下这种思路排序开的空间太大了,就比如要排序的数全部在1000~2000之间的数,我们从0开始开空间,那么前1000的空间就是白开了,造成很大的空间浪费。
我们可以先进行遍历,找到要排序数组中最大值和最小值,两者作差再加1,就是我们需要开的空间。
代码如下

//基数排序
void CountSort(int* a, int n)
{
	int min = a[0], max = a[0];
	for (int i = 0; i < n; i++)
	{
		if (a[i] < min)
		{
			min = a[i];
		}
		if (a[i] > max)
		{
			max = a[i];
		}
	}
	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
		perror("malloc fail");
		return;
	}
	memset(count, 0, sizeof(int) * range);
	//统计数据出现的次数
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;//开的空间是减去min的,所以排序数组中的数在存储时也要减去min。
	}
	int j = 0;
	for (int i = 0; i < range; i++)
	{
		while (count[i]--)
		{
			a[j++] = i + min;//该位置的数出现几次,就统计出几次
		}
	}
}

基数排序总结

  1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。如果是小数呢?你就无法用下标进行存储了。
  2. 时间复杂度:O(N(范围))
  3. 空间复杂度:O(N)

OK,介绍5个用到该思想的题目,帮大家掌握住这种做题方法
1,错误的集合
在这里插入图片描述
这道题的解法很多
 思路一:最容易想到的就是先排序,然后就可以很轻易的找到消失的数字,而且我们已经知道了包含1到n,可以直接求和减去出现差错的数组中的所有元素,例如将5复制成了7,减完之后结果为-2,那么重复的数就是5加上2为7。
 思路二:直接利用基数排序的思想。重新开一个数组(初始化全部为0),不用排序,直接用所给集合里面的所有数对应的下标位置加加,当然,如果没出现某个数,那么新开数组这个位置的数就是0,重复的就是1。
代码如下

int* findErrorNums(int* nums, int numsSize, int* returnSize)
{
    int *array1,*array2,i;
    array1=(int*)calloc(numsSize,sizeof(int));
    array2=(int*)malloc(sizeof(int)*2);
    for(i=0;i<numsSize;i++)
    {
        array1[nums[i]-1]+=1;
    }
    for(i=0;i<numsSize;i++)
    {
        if(array1[i]==2)
        array2[0]=i+1;
        else if(array1[i]==0)
        array2[1]=i+1;
    }
    *returnSize=2;
    return array2;    
}

 逻辑清晰,时间复杂度为O(N),空间复杂度为O(N)。当然也可以加一个判断,当已经找到两个数字后直接跳出循环,减少循环次数。


2,字符个数统计
在这里插入图片描述

 同样还是找一段区间中是否存在某个数,或者某个数出现的次数,字符也是整形,可以利用字符表示的整形还是同样依照上边的那种思路进行解题只需要强制转化,其他思路全部相同。
代码如下

#include <stdio.h>
int main() {
    int i = 0;
    int count = 0;
    char arr1[500];
    int arr[127] = { 0 };

    scanf("%s", arr1);
    while (arr1[i] != '\0')
    {
        arr[(int)arr1[i]] = 1;
        i++;
    }
    for (int j = 0; j < 127; j++)
    {
        if (arr[j] == 1)
        {
            count++;
        }
    }
    printf("%d", count);
    return 0;
}

 同样,只要使用这种思路时间复杂度一般都是O(N),由于题目都说了,范围在0~127之间,用这种思路多爽啊。


3,多数元素
在这里插入图片描述
 给定数组,找到数组中出现次数大于numsSize/2的数,我们还可以使用这种方法,但是这道题使用这种方法跑不过,虽然已经知道了我们要开多少的空间(时间复杂度为O(1)),但是数组中数的最大值和最小值相差2*10^9,这个数字太大了,意味着我们要开的空间也是非常大的,这道题要想用时间复杂度为O(N),用这种方法是跑不过的。但是可以骗骗分,正如上边所说,介绍的是一种思路而已,当然还会给出另外的解法。
利用数组下标做法代码如下啊

int majorityElement(int* nums, int numsSize) {
    int min = nums[0], max = nums[0];
	for (int i = 0; i < numsSize; i++)
	{
		if (nums[i] < min)
		{
			min = nums[i];
		}
		if (nums[i] > max)
		{
			max = nums[i];
		}
	}
    int range=max-min+1;
    int*arr=(int*)malloc(sizeof(int)*(range));
    for (int k = 0; k < range; k++)
	{
		arr[k] = 0;
	}
    for (int i = 0; i < numsSize; i++)
	{
		arr[nums[i] - min]++;
	}
	for(int j=0;j<range;j++)
    {
        if(arr[j]>numsSize/2)
        {
            return j+min;
        }
    }
	return -1;
}

 仔细观察可以发现和前边基数排序的方法手段如此相像,只不过在存储完成后要判断或得到的东西不同而已。
用这个代码跑的话,是通过不了的,因为某些用例专门针对。
在这里插入图片描述
可以发现,过了大部分用例
在这里插入图片描述
 剩下的估计都含有这两个数字,不知道优化能不能成功,也不想费那么多事,如果用例中数组内的数字差别没有这么大,那么这种解法的时间复杂度为O(N),空间复杂度为O(1)。

OK,不能就这么摆着一个不能通过的方法在这里

谈一谈投票法(很巧妙)
 利用该数组中多数元素的次数绝对大于numsSIze/2这一特性,所以用不同的元素消去相同的对象,那么身下到最后的绝对是相同元素,即我们要找的多数元素。
在这里插入图片描述
代码如下

int majorityElement(int*nums,int numsSize)
{
    int candidate=nums[0];
    int flag=1;
    for(int i=1;i<numsSize;i++)
    {
        if(nums[i]==candidate)
        {
            flag++;
        }
        else
        {
            flag--;
            if(flag<0)
            {
                candidate=nums[i];
                flag=1;
            }
        }
    }
    return candidate;
}

4,找到所有数组中消失的数据
在这里插入图片描述

 同样,这道题也是与数组中某个数字是否存在或者某个数字出现了几次的问题,利用同样的思路,不需要排序即可找出,且时间复杂度为O(N),但是我们开了额外的空间,至于进阶的写法,先放一放。
代码如下

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize){
    int k=0;
    int*arr=(int*)malloc(sizeof(int)*(numsSize));
    int*ret=(int*)malloc(sizeof(int)*(numsSize));
    //memset(arr,0,(sizeof(int)*(numsSize+1)));
    for(int l=0;l<numsSize;l++)
    {
        arr[l]=0;
    }
    for(int i=0;i<numsSize;i++)
    {
        arr[nums[i]-1]++;
    }
    for(int j=0;j<numsSize;j++)
    {
        if(arr[j]==0)
        {
            ret[k++]=j+1;
            //*returnSize++;
        }
    }
    *returnSize=k;
    return ret;
}

总结:判断数组中某数(尤其是无序)出现的个数(判断有没有出现就是出现个数是不是0嘛),就可以使用这种方法,和基数排序原理一样,空间换时间,开空间时一定要的。
 结束啦结束啦,希望你有所收获,这就是我创作的最大动力。

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

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

相关文章

ESP32单片机案例

工具&#xff1a;VScode PlatformIO IDE 注&#xff1a;B站视频学习笔记。 1、继电器 1&#xff09;硬件电路 2&#xff09;程序 #include <Arduino.h> #define RELAY_PIN 15//初始化定时器 hw_timer_t *timer NULL;void timer_interrupt(){digitalWrite(RELAY_PIN…

文件中找TopK问题

目录 1.解题思路2.创建一个文件并在文件中写入数据3.为什么要建立小堆而不建立大堆&#xff1f;4.如何在现有的数据中建立适合的大堆&#xff1f;5.代码实现 1.解题思路 TopK问题即是在众多数据中找出前K大的值&#xff0c;则可以根据堆的性质来实现&#xff0c;但在使用堆之前…

敌手觊觎,核心研发项目源代码安全不可忽视!立即了解迅软DSE防泄密良策!

源代码作为企业的知识产权之一&#xff0c;也是企业的重要商业秘密&#xff0c;如果不慎被泄露可能会被竞争对手利用&#xff0c;对企业的业务和安全带来威胁以及不必要的法律风险。面对层出不穷的泄密事件&#xff0c;相关人员更应该提高对源代码的保护意识&#xff0c;加强企…

K歌利器-无线K歌麦克风模组-投影K歌解决方案

麦克风K歌模组是一种用于改善音频质量的麦克风系统&#xff1b;其发展可以追溯到20世纪50年代&#xff0c;如今&#xff0c;麦克风模组的技术发展已经非常成熟&#xff0c;可以提供更为优质的音频质量&#xff1b;支持多种不同的连接方式&#xff1b;可以在不同的设备上使用。 …

a-select:下拉组件实现筛选+远程搜索功能——基础积累

a-select:下拉组件实现筛选远程搜索功能——基础积累 效果图下拉筛选数据&#xff1a;远程搜索功能&#xff1a; 效果图 下拉筛选数据&#xff1a; <a-selectshow-searchv-model"form.jobPositionCode"placeholder"请选择岗位"style"width: 100%&q…

『Jmeter超级干货』| Linux下Jmeter安装配置、脚本设计执行、监控及报告完整过程

『Jmeter超级干货』| Linux下Jmeter安装配置、脚本设计执行、监控及报告完整过程 1 JDK安装部署1.1 JDK下载1.2 JDK配置 2 Jmeter安装部署2.1 Jmeter下载2.2 Jmeter安装2.3 Jmeter相关目录配置2.4 Jmeter启动配置2.5 检查并启动 3 Jmeter汉化3.1 临时修改3.2 永久修改 4 准备测…

Modbus TCP工业RFID读写器的选型要点

Modbus TCP工业RFID读写器是一种采用Modbus TCP通信协议的RFID读写器。它可以通过TCP/IP网络与计算机或其它设备进行通信&#xff0c;实现远程读取和写入RFID标签数据的目的。 与传统的RFID读写器相比&#xff0c;Modbus TCP工业RFID读写器具有更远的读写距离、更高的读写灵敏度…

CAD精品Eyeshot Fem 2023.3.630 -2023-11-05 Crack

2023.3.630 更新25天前 分享 跟随还没有人关注 改进的 Brep.TransformBy() 方法修复了工具栏内存泄漏修复了 glTF 材质导出期间的异常改进了 glTF 材质金属粗糙度设置修复了渐进式绘图和剪辑平面的错误在 Workspace.UseShaders 属性设置器中添加了缺少的 RenderContext.MakeCur…

Python 计算图像差分的三种方式(cv2,torchvision,numpy)

前言&#xff1a;最近在可视化图像残差时&#xff0c;发现几种不同的差分方法&#xff0c;下面分别给出每种差分方法的实现方式&#xff0c;并比较不同方法之间的差异。 目录 1️⃣ cv22️⃣ PIL & torchvision3️⃣ PIL & numpy 目标&#xff1a;对于给定的下述两张图…

Windows系列:Windows server 2016 部署路由与远程访问服务

Windows server 2016 部署路由与远程访问服务 前言环境要求服务器配置ip 设置"远程访问" 服务安装 "远程访问" 服务配置 ”远程访问“ 服务新建用户 客户机配置添加VPNping 前言 千万不要安装图上的几个服务&#xff0c;如果安装了&#xff0c;鼠标会失灵…

10.0 输入输出 I/O

IO操作主要是指使用Java程序完成输入&#xff08;Input&#xff09;、输出&#xff08;Output&#xff09;操作。所谓输入是指将文件内容以数据流的形式读取到内存中&#xff0c;输出是指通过Java程序将内存中的数据写入到文件中&#xff0c;输入、输出操作在实际开发中应用较为…

键盘打字盲打练习系列之指法练习——2

一.欢迎来到我的酒馆 盲打&#xff0c;指法练习&#xff01; 目录 一.欢迎来到我的酒馆二.指法练习 二.指法练习 前面一个章节简单地介绍了基准键位、字母键位和数字符号键位指法&#xff0c;在这个章节详细介绍指法。有了前面的章节的基础练习&#xff0c;相信大家对盲打也有了…

构建智能预约体验:深度解析预约系统源码的代码精髓

随着数字化时代的发展&#xff0c;预约系统在各行业中扮演着越来越重要的角色。本文将深入研究预约系统源码&#xff0c;通过代码示例分析其技术要点&#xff0c;为开发者提供实用的指导&#xff0c;助力构建智能、高效的预约体验。 技术栈综述 预约系统源码采用了现代化的技…

【JUC】十八、happens-before先行发生原则

文章目录 1、先行发生原则happens-before2、happens-before总原则3、8条happens-before规则4、案例 1、先行发生原则happens-before 在Java中&#xff0c;Happends-Before本质上是规定了一种可见性&#xff0c; A Happends-Before B&#xff0c;则A发生过的事情对B来说是可见的…

大模型fine-tune 微调

大模型的 Fine-tune 我们对技术的理解&#xff0c;要比技术本身更加重要。 正如我在《大模型时代的应用创新范式》一文中所说&#xff0c;大模型会成为AI时代的一项基础设施。 作为像水、电一样的基础设施&#xff0c;预训练大模型这样的艰巨任务&#xff0c;只会有少数技术…

滚珠丝杆在各种自动化设备中的作用

滚珠丝杆因其具有高精度、高刚度和长寿命等特性&#xff0c;成为许多设备中的重要组成部分&#xff0c;在许多行业中都有广泛的应用&#xff0c;接下来我们看看滚珠丝杆的具体应用有哪些&#xff1f; 1、打孔机&#xff1a;提供精确的导向&#xff0c;使打孔机的滑块能够沿固定…

数据库管理-第119期 记一次迁移和性能优化(202301130)

数据库管理-第119期 记一次迁移和性能优化&#xff08;202301130&#xff09; 1 迁移 之前因为DV组件没有迁移成功的那个PDB&#xff0c;后来想着在目标端安装DV组件迁移&#xff0c;结果目标端装不上&#xff0c;而且开了SR也没看出个所以然来。只能换一个方向&#xff0c;尝…

优化-查询数据接口太慢

有一个查询接口&#xff0c;主业务表有几万多条数据&#xff0c;没超过十万&#xff0c;由于没有使用分页&#xff0c;所以每次查询都要返回大几万的数据&#xff0c;然后问题是前端页面查询数据显示数据要转很久。 压缩响应体大小 我发现查询的时间是1秒多&#xff0c;但是浏…

Android中在google Map 上绘制历史路径

很多的App都会有这种需求&#xff0c;需要把自己的轨迹绘制在地图上来加标一段行踪&#xff0c;使得自己的行程展现出来&#xff0c;通过地图的展示&#xff0c;自己的行程也就一目了然了。 这里利用Google Map 把自己的行程展现出来&#xff0c;注意这里用到了上一章的基础&a…

关于最近Facebook的未经用户同意收集使用个人信息,

最近收到深圳市通信管理局的违法违规APP处置通知大概如下: 并且详细列举了 facebook sdk 在未经用户允许前调用的 TelephonyManager.getNetworkOperatorName(); 方法,获取运营商名称. 解决方法, 首先 在用户没有点击允许隐私条款前 不要调用任何Facebook sdk 方法,比如: Fac…