剑指offer——数组中重复的数字
写完了二维数组中的查找之后,据相同知识点,找到了这个题,原题目地址:数组中重复的数字。
为方便直接看,先抄写一下题目:
题目描述:
在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如,输入长度为7的数组{2,3,1,0,2,5,3};那么对应的输出是第一个重复的数字2。
题目分析:
首先可以判断出来数组是一维的。然后需要找到任意一个重复的元素,将其输出。
但是题目中并没有说数组是有序的。
第1个方法:为数组排个序,然后比较相邻的两个元素是否相等。
第2个方法:另外创建一个数组,从该数组中取出元素放入新数组;放入之前先比较新数组中是否有该元素,若有,则该数重复。
对于方法1,涉及到数组的排序,复杂度比较高,所以不太合适;对于方法2,则相对减少了比较的次数,但是多开辟了空间。该方法的实现代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public boolean duplicate(int numbers[],int length,int [] duplication) { //开辟一个空间存储各类别的数字方法 if(numbers == null || length <= 0){ return false; } int[] element = new int[length]; element[0] = -1; int ele = 1; for(int i=0; i<length; i++){ for(int j=0; j<ele; j++){ if(numbers[i] == element[j]){ duplication[0] = numbers[i]; return true; } } element[ele-1] = numbers[i]; ele++; } return false; }
这种方法有点小问题:由于创建int型数组时会自动赋初值为0;所以当出现0元素时,该方法将无法正确判断。要保证正确,则需要使初始化数组不为0,经过查找,发现对于int型的数组,要初始化为指定数值,则需要遍历每个元素进行赋值。所以此方法又额外增加了很大的负担。
再仔细阅读题目,可以发现:数组的长度为n,数字在0到n-1的范围,说明当且仅当数组中的元素恰好为0到n-1这n个数时,数组是不重复的;其他情况都有重复的数字。
利用数组本身的特性,我们不妨将数组进行这样的排序:
将每个元素放到与下标一致的位置,若存放某个元素时,发现该下标位置已经存在一个相同的元素,说明该元素重复。这样操作可以一边排序一边查找。实现代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public boolean duplicate(int numbers[],int length,int [] duplication) { //交换元素到对应下标位置 if(length <= 0 || numbers == null){ return false; } //用于交换的中间变量 int swap = -1; //数组下标起始位 int tag = 0; while(tag < length){ //数组对应下标的元素 int num = numbers[tag]; //若元素值等于下标值,则下标自加 if(num == tag){ tag++; }else{ //否则以元素值作为下标值,判断该下标值处的元素是否和下标值相等 if(numbers[num] == num){ //若已相等,说明该元素值重复 duplication[0] = num; return true; }else{ //若不相等,则交换两个元素,使后者位置元素与下标相等 swap = num; numbers[tag] = numbers[num]; numbers[num] = swap; } } } return false; }
此代码在牛客网上运行时间为27ms。