【数组中重复的数字】-C语言-题解
原题链接:数组中重复的数字
一、描述:
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
二、样例:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:
2 或 3
三、数据范围:
2 <= n <= 100000
四、题解
1. 利用下标索引
即通过创建额外的数组空间用来记录各个数出现的次数,具体实现方法是:
(1)创建数组,并将数组元素初始化为0
(2)遍历原数组,以出现的数作为用于计数的数组的下标,该下标所对应的计数数组中的元素++
(3)计数数组中的元素若大于1,则该元素所对应的下标就是原数组中那个重复的数字。
以样例为例:
设计数数组为count[100001]
,则遍历原数组后可得到:
count[0] == 1;
count[1] == 1;
count[2] == 2;
count[3] == 2;
count[5] == 1;
故2或3就是原数组中重复的数
- 完整代码:
int findRepeatNumber(int* nums, int numsSize)
{int hash[100001] = {0};int i = 0;for(i = 0; i < numsSize; i++){if(++hash[nums[i]] > 1)return nums[i];}return 0;
}
复杂度分析:
使用了额外的空间,空间复杂度O(n);
遍历整个数组,时间复杂度O(n)。
2. 原地置换(重点学习)
顾名思义,算法的主要思想就是在原数组的基础上根据不同索引值进行数据的置换,然后根据置换的结果,就可以判断出那个重复的数,下面详细介绍。
介绍之前,先总结列出文中相关句段所对应的代码段,可能会便于理解一些:
设循环遍量为 i ,则:
当前元素或者说以 i 为下标索引得到当前元素表示为:nums[i]
以循环变量 i 作为直接索引得到当前元素表示为:i == nums[i]
以当前元素本身 作为数组下标索引得到当前元素表示为: nums[nums[i]] == nums[i]
这里再规定一下 “正确的位置” 的含义以便说明:
“正确的位置” 代表该元素正好就是以该元素本身为数组下标索引所得的元素。如:数组arr[5] = {0, 2, 1, 3, 6}
,其中的元素0与元素3就处于 “正确的位置” ,因为arr[0] == 0
,arr[3] == 3
。
(1)算法思想:遍历数组,每遇到一个元素就检查该元素是否位于正确的位置上:
- 先以循环变量
i
作为直接索引进行检查,即if(i == nums[i])
,若符合条件则说明,此时元素恰好位于正确的位置上(原来在数组中就处于正确位置或交换后处于正确位置),那么就执行i++
跳过而检查下一个元素; - 再以该元素本身作为下标索引进行检查,即
if(nums[nums[i]] == nums[i])
,若符合条件则说明,此元素在之前已经出现过,出现时的位置要么恰好是正确的位置,要么是经过交换来到了正确的位置,因此该元素就为重复元素; - 若都不符合两种检查方式的条件,则说明元素不在正确的位置上,那么需与相对当前元素来说的正确位置上的元素进行交换,从而让该元素元素处于正确位置;但需要注意的是,交换可以让当前元素处于正确的位置上,但不能保证被交换的元素处于正确的位置上,所以在执行完交换后
i
不进行++
,直到使两个交换的元素都处于正确的位置上后,才由条件if(i == nums[i])
来控制i的++。(后面有例)
由如上描述可知,符合第一种情况的一定符合第二种情况,即:若有i == nums[i]
,则必有i == nums[i] == nums[nums[i]]
;反之则不一定成立,这个不一定成立的情况,也正是重复元素的情况,即有 nums[i] == nums[nums[i]]
,但同时i != nums[i]
总结来说就是:利用原地置换处理的数组,对于数组中的不重复的元素必有i == nums[i]
; 当不满足这个条件,且满足 nums[i] == nums[nums[i]]
条件时,nums[i]
就是重复的元素
(2)样例说明:对于数组 [2, 3, 1, 0, 2, 5, 3],原地置换的过程如下:
- 当
i = 0
时,当前元素nums[i] = 2
, 元素 2 不在正确的位置上,且以该元素本身为下标索引找到的元素 1 不等于当前元素,所以将其与以2为下标的数组元素进行交换,交换结果为: [1, 3, 2, 0, 2, 5, 3]; - 交换完后发现当前元素
nums[i] = 1
,元素 1 不在正确的位置上,且以该元素本身为下标索引找到的元素 3 不等于当前元素执行交换,交换结果为:[3, 1, 2, 0, 2, 5, 3] - 交换完后发现当前元素
nums[i] = 3
,元素 3 不在正确的位置上,且以该元素本身为下标索引找到的元素 0 不等于当前元素,执行交换,交换结果为:[0, 1, 2, 3, 2, 5, 3] - 交换完后发现当前元素位于正确位置,
i++
跳过,进行下一个数的检查,由此,i一直++到4; - 当
i = 4
时,当前元素nums[i] = 2
不在正确的位置上,但以该元素本身为下标索引能到的元素 2 等于当前元素,说明当前元素为重复元素,返回当前元素 2 - (3)形象理解:
此形象理解来源于原题题解下的评论,这里转述一下,供大家参考:
这个原地交换法就相当于分配工作,每个索引代表一个工作岗位,每个岗位必须专业对口,即0索引必须是0元素的“专业人才”才能上岗。而我们的目的就是通过专业对口的方式找出溢出的人才。我们先从0索引岗位开始遍历,首先我们看0索引岗位是不是已经专业对口了,如果已经专业对口即nums[0]=0,那我们就跳过0岗位看1岗位。如果0索引没有专业对口,那么我们看现在0索引上的人才调整到他对应的岗位上,比如num[0]=2,那我们就把2这个元素挪到他对应的岗位num[2]上,这个时候有两种情况:1、num[2]岗位上已经有专业对口的人才了,既num[2]=2,这就说明刚刚那个在num[0]上的2是溢出的人才,我们直接将其返回即可。2、num[2]上的不是专业对口的人才,那我们将num[0]上的元素和num[2]上的元素交换,这样num[2]就找到专业对口的人才了。之后重复这个过程直到帮num[0]找到专业对口的人才,然后以此类推帮num[1]找人才、帮num[2]找人才,直到找到溢出的人才。
(4)算法实现注意事项:
- 检查的次序问题:如上所述,应先检查
if(i == nums[i])
,再检查if(nums[nums[i]] == nums[i])
- 交换注意问题:这里用一个错误的代码作为例子,请看:
tmp = nums[i];nums[i] = nums[nums[i]];nums[nums[i]] = tmp;
这样的交换存在问题:在执行完第二句语句时,nums[i]
的值已被改为nums[nums[i]]
,故在第三句语句用nums[i]
来作为数组下标索引时就达不到我们预期的效果,最后一句语句我们想的把nums[i]
的值赋给nums[nums[i]]
,而如上代码相当于是把nums[i]
的值赋给了nums[nums[nums[i]]]
,这就出现问题了。
正确更改方式为,把最后一句语句中的nums[i]
作为下标索引改为tmp
作为下标索引,即:nums[tmp] = tmp;
复杂度分析:
使用了常数复杂度的空间,空间复杂度O(1);
遍历整个数组,时间复杂度O(n)。
- 完整代码:
int findRepeatNumber(int* nums, int numsSize)
{int i = 0;int tmp = 0;while(i < numsSize){if(i == nums[i]){i++;continue;}if(nums[i] == nums[nums[i]])return nums[i];if(i != nums[i]){tmp = nums[i];nums[i] = nums[nums[i]];nums[tmp] = tmp;//nums[i]的值已变,故要用tmp索引}}return -1; //没有重复的元素返回-1
}
看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或看不懂的地方或有可优化的部分还恳请朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹
相关文章:
【数组中重复的数字】-C语言-题解
原题链接:数组中重复的数字 一、描述: 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数…...

C++调用Python脚本进行18次循环操作后,脚本不执行
C调用Python脚本进行18次循环操作后,脚本不执行 现象: 发送端接收端 从第二张图中可以看出,python脚本卡在’[parkin_debug] 6’与’[parkin_debug] 7’之间 该测试经过多次反复测试,均在第18次循环执行时,出现上述问…...

字节10年架构师职业发展经历,助你做好职业规划
一直以来程序员这一职业都给人高薪资的印象,近年来随着互联网行业的快速发展,程序员更是人满为患,然而很多人关注的却是程序员的薪资,而非职业本身。 一批批程序员进入工作岗位,但是很多人并没有对自己的职业生涯有清…...
ArrayList真的是因为实现了RandomAccess接口才能做到快速随机访问的吗
ArrayList和RandomAccess接口RandomAccess 接口Collections.binarySearch()源码总结RandomAccess 接口 首先,RandomAccess接口是什么,以下代码可见: public interface RandomAccess { }RandomAccess接口其实是一个标记接口,它只…...

OSI七层模型与物理层与设备链路层
目录 协议 举例 OSI七层模型 理解七层模型 以下为OSI七层模型数据逐层封装和数据逐层解封的过程 TCP/IP参考模型 数据包的层层封装与层层拆包 各层的数据以及协议 封装所用的协议的数字表示形式 物理层 模拟信号 模拟信号特点 数字信号 数字信号特点 数据通信模…...

Java8的Optional类的使用 和 Stream流式操作
Java知识点总结:想看的可以从这里进入 目录13.6、Optional类13.7、Stream13.7.1、Stream创建13.7.2、中间操作1、筛选2、切片3、映射4、排序13.7.3、终止操作1、遍历2、聚合3、匹配查找4、归约5、收集归集统计分组字符串拼接归约13.6、Optional类 Optional类是一个…...

Authorization Server 认证服务
Hi Auth HiAuth是一个开源的基于Oauth2协议的认证、授权系统,除了标准的Oauth2授权流程功能外,还提供了应用管理、用户管理、权限管理等相关功能。 在这个项目中你能够了解到如何基于spring-security-oauth2-authorization-server实现自己的Authorizat…...
研制过程评审活动(五)生产定型阶段
1. 生产定型阶段主要任务 生产定型的主要任务是对产品批量生产条件和质量稳定情况进行全面考核,以确认产品是否达到批量生产的标准。 需要生产定型的军工产品,在完成设计定型并经小批量试生产后、正式批量生产之前,进行生产定型。生产定型的条件和时间,由定委在批准设计…...
NCUT加权的NMF
矩阵定义 X:特征矩阵,矩阵的维度为体素数mx(指标数x被试数)n S:相似性矩阵,由特征矩阵的每一行计算皮尔逊相关得到mxm的方阵 D:度矩阵,度矩阵的对角线元素由相似性矩阵S对应的行和…...

从0开始的ios自动化测试
最近由于工作内容调整,需要开始弄ios自动化了。网上信息有点杂乱,这边我就按我的实际情况,顺便记录下来,看是否能帮到有需要的人。 环境准备 安装tidevice pip3 install -U “tidevice[openssl]” 它的作用是,帮你绕…...

vue3中使用jszip压缩文件
1、安装依赖 npm install jszip npm install file-saver --save 2、使用 <template><el-card class"mb15"><template #header><span>jszip</span></template><!-- 二维码容器 --><div id"qrCodeBox">&…...

React 虚拟DOM的前世今生
引文 通过本文你将了解到 什么是虚拟DOM?虚拟DOM有什么优势?React的虚拟Dom是如何实现的?React是如何将虚拟Dom转变为真实Dom? 一、前言 要了解虚拟DOM,我们先明确一下DOM的概念。 根据MDN的说法: 文档…...
Java环境变量配置
一、Path环境变量配置设置环境变量的值:C:\Program Files\Java\jdk-17\bin目前较新的JDK安装时会自动配置javac、java程序的路径到Path环境变量中去 ,因此,javac、java可以直接使用。注意:以前的老版本的JDK在安装的是没有自动配置…...

超详细解读!数据库表分区技术全攻略
更多内容可以关注微信公众号:老程序员刘飞 分区的定义 分区是一种数据库优化技术,它可以将大表按照一定的规则分成多个小表,从而提高查询和维护的效率。在分区的过程中,数据库会将数据按照分区规则分配到不同的分区中࿰…...

Redis高可用集群方案
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 @[TOC](文章目录)主从复制哨兵模式(sentinel)Cluster集群在生产过程中,Redis不一定会单独部署。因为一旦redis服务因为某些原因导致无法提供数,那么redis就不可用了。那么实现redis高可用的方式就…...

企业微信机器人发送消息
前言 随着科技的发展,各企业公司的业务不断发展,那么就需要强有力的沟通软件,其中企业微信、钉钉的能力得到了大众的认可,今天这篇文章就讲其中的一个功能-调用企业微信机器人(下文简称应用)进行消息传递。它的好处有哪些呢?自然是可以让相关人员及时追踪任务进度。 一、…...

使用PHP+yii2调用asmx服务接口
一.创建服务端 1:创建一个ASP.NET web应用程序 2:选择空的模板 3:系统生成项目目录 4:右键项目-添加项-新建项 5:选择Web 服务(ASMX) 6:选择之后项目中会有一个Test.asmx服务程序,…...
【042】904. 水果成篮[滑动窗口]
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果&…...
Linux基础知识(一)
♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放࿰…...
Redis面试题
目录 Redis持久化机制:RDB和AOF Redis线程模型有哪些?单线程为什么快? Redis的过期键有哪些删除策略? Redis集群方案有哪些? redis事务怎么实现? 为什么redis不支持回滚? redis主从复制的原理是什么 …...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql
安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了,系统很多命…...

PLC入门【4】基本指令2(SET RST)
04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C),从 文件 - 主画面,“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…...