剑指offer-----数组中重复的数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

第一种:最朴素的做法

    可以使用排序方法来做,例如使用快排等。然后再遍历一次数组就可以找到重复的数字了。时间复杂度是O(nlogn)。这是我目前知道的算法中,时间复杂度较好的。

第二种:利用空间换取时间

  我们可以使用HashMap来保存我们迭代过程中遍历的值,在迭代过程中,如果发现HashMap里面包含了我们目前遍历到的值,则可以直接放回该值了。时间复杂度是O(n),空间复杂度也是O(n)。

  使用其他数据结构也都是可以,不过第二种方法我们可以再进行优化一下。

第三种:最推荐,时间复杂度是O(n),空间复杂度是O(1)

  这里有一个关键点(第三种方法需要这个前提条件),就是该数组元素的值都是在0 ~ n-1 的范围内。

 为了方便理解(第三种做法),让我先借助一个布尔数组,生成一个长度为n的布尔数组。

      我们可以一边遍历元素,一遍让元素的值作为下角标,先访问布尔数组对应位置的值,如果为false,我们就设置为true,然后继续数组的遍历;如果已经是true,那么该下角标的数值就是我们要的答案。

 

 

注意注意: 下面开始讲重点了(敲黑板~~~~~)

  我们使用一个布尔数组就是为了标记我们遍历过这个数字。那么,我们能不能在遍历的过程中,在原数组上面下手呢?

  当然是可以,因为我们有上面提到的那个关键点:数组元素的值都是0 ~ n-1的范围内。  为了方便,我们将array作为我们需要寻找重复数字的数组。

  所以,在迭代过程中,我们将目前访问的元素的值作为下角标(例如某数字x),将array[x] 加上 我们数组的长度(相当于设置为true)。当然在赋值之前判断一下array[x] 是不是 大于等于 length(小于length,可以理解为false),是的话,x就是我们要的答案。在迭代过程中,元素里面的值有可能大于等于length,在作为下角标时,我们需要先进行求模运算,再查找。

  

  本人文才不好,可能这上面一段话会让人看不懂。 所以,我们不妨这样看,用元素的值作为下角标,我们就具体地作为数字看,大于等于length的,就求模;  通过元素的值作为下角标  访问到的  值 ,当成布尔值。小于length的,当成false;大于等于length的,当成true,且下角标就是我们要的答案。

 

例子:

   {2,3,1,0,2,5,3},长度为7

  第一次迭代: index = array[0] ,array[index] 为 1。是false(值小于7),需要将其设置为true (值加上7) ,数组就变成了{2,3,8,0,2,5,3}

  第二次迭代:  index = array[1] ,array[index] 为 0 。还是false 。处理与第一次迭代一样。之后数组变成

{2,3,8,7,2,5,3}

  第三次迭代: index= array[2] ,元素值大于length了,经过求模7后,index = 1,array[index] =3 ,相同处理,数组变成

{2,10,8,7,2,5,3}

  第四次迭代后,数组变成{9,10,8,7,2,5,3}

  第五次迭代:  index = array[4], array[index] =8,是true(大于等于length),所以index 就是第一个重复的数字,是2。

   结束迭代。

 

 

  下面附上代码:

public boolean duplicate(int numbers[]) {
        if(numbers == null)
            return false;
        int length = numbers.length;
        int result = -1;
        int index = 0;
        for(int i = 0;i < length;i++){
            index = numbers[i];
            //将元素的值作为下角标,大于等于length的就需要进行求模运算
            if(index >= length)
                index = index % length;
            //如果是true
            if(numbers[index] >= length){
                result = index;
                break;
            }else if(numbers[index] < length){
            	//如果为false
                numbers[index]+= length;
            }               
        }     
        System.out.println(result);
        //等于-1就是没有重复数字
        if(result < 0)
        	return false;
        else 
        	return true;
    }

 

   文笔不好,请见谅! 如果有错,欢迎提出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值