百道经典算法题——数组中的重复的数字

(你能想到所有解法吗?)

找出数组中重复的数字

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例:

输入:[2, 3, 1, 0, 2, 5, 3]
输出:23 

限制:

2 <= n <= 100000

解法详谈:

题目看似简单,但实际上是考察对空间复杂度以及时间复杂度的掌握是否到位,下面我们来进行详细的分析(代码均为C语言):

方法一: 使用双重循环,对数组nums中的值依次遍历,查找之后是否存在相同元素,有的话就直接return。这是最笨的方法,当数组较大时,执行起来非常慢,时间复杂度O(n^2),空间复杂度O(1)

int findRepeatNumber(int* nums, int numsSize){
    for(int i = 0;i<numsSize;i++)
        for(int j = i+1;j <numsSize;j++)
            if(nums[i]==nums[j])
                return nums[i];
    return 0;
}

方法二: 先对数组nums进行排序(这里选择的快排),然后看相邻元素是否有相同的,有相同元素的话就直接return。 执行较慢,时间复杂度O(nlogn),空间复杂度O(1)

int findRepeatNumber(int* nums, int numsSize){
    qsort(nums, numsSize, sizeof(int), comp);
    for (int i = 1; i < numsSize; i++) {
        if (nums[i - 1] == nums[i])
            return nums[i];
    }
    return 0;
}

方法三: 前两种方法在时间复杂度方面都较高,如果想降低时间复杂度。题目中表示数组nums中的数值在 0~n-1 的范围内,那我可以采用典型的以空间换时间的方法,声明一个长度为n的辅助数组a,以nums数组中数值来作为数组a的下标,从而对数组a中值进行判断是否存在相同元素。这里提醒大家的是一般碰到数组nums中的数值在 0~n-1 的范围内 这种条件时,都是可以考虑此种方法。

int findRepeatNumber(int* nums, int numsSize){
    int *a=(int *)malloc(sizeof(int)*numsSize);
    int i,j;
    for(i=0;i<numsSize;i++){
        a[i]=0;
    }
    for(i=0;i<numsSize;i++){
        if(a[nums[i]]==0){
            a[nums[i]]++;
        }else{
            return nums[i];
        }
    }
    return 0;
}

方法四:题目中表示数组nums中的数值在 0~n-1 的范围内,所以数组的值和下标大小范围是一样的。那我们可以从头到尾扫描这个数组中的每个数字,当出现改位置数字不相等的时候,假设当前索引为i,值为j,若 i ≠ j i \neq j i=j,则交换i和j。若二者相等,说明找到一个重复数字。这么交换下去,直到碰到重复数字,或者整个遍历结束。

int findRepeatNumber(int* nums, int numsSize){
    for(int i = 0;i<numsSize;i++)
        while(i!=nums[i]){
            if(nums[i]==nums[nums[i]])
                return nums[i]
            else{
                temp = nums[i]
                nums[i] = nums[nums[i]]
                nums[temp] = temp
            }
        }
    return 0;
}

值得注意的是,当题目中出现了数值在 0~n-1 的范围内 大家就要能想起方法三、四,并加以运用。
上述方法中在查找重复元素时,碰到首个重复元素就停止查找了,如果想找出所有的重复元素该怎么办呢?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值