剑指 Offer 03. 数组中重复的数字(C)

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


⭐️题目来源


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


示例 1:

输入:

[2, 3, 1, 0, 2, 5, 3]

输出:

2 或 3


限制:

2 <= n <= 100000


方法一:直接遍历(超出时间限制)



思路:将数组中的每一个数字和后面的所有数字进行比较,当发现相等时,即为结果。

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

85505299e2d74ac89f3408a69438b144.png


方法二:排序 + 遍历(执行用时:32 ms 内存消耗:10.5 MB)


思路:排序后能保证重复的数字连续分布,这样遍历时只需要比较当前数字和下一个数字是否相同即可。


这里需要用到C语言本身的库函数qsort–>如果不清楚的小伙伴可以看看这篇博客

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

702c932f1d41439ba9f0a6572e9b1f13.png


方法三:哈希查找(执行用时:28 ms 内存消耗:10.4 MB)



思路:创建哈希数组(key:数字,value:出现次数),遍历时先检查当前索引对应的数字是否已经出现,出现则返回结果,否则更新该数字出现次数。

#define NUMS_SIZE  100000
int findRepeatNumber(int* nums, int numsSize){
    int numsHash[NUMS_SIZE]={0};
    for(int i=0;i<numsSize;i++)
    {
        if(numsHash[nums[i]]>0)
        {return nums[i];}
        numsHash[nums[i]]++;
    }
    return -1;
}

653dfd96f53a440fa6875e02be6bfd02.png


方法四:原地排序(执行用时:24 ms 内存消耗:10.3 MB)



思路:借用输入数组,将当前索引对应的数字,替换到对应的数字索引下,保证索引和数字相等。如果出现替换时,索引和数字已经相等时,说明该数字重复,返回结果。相比于思路三的优点是不需要申请额外的空间存放Hash表。执行过程如下图。

d487c638c9584945adcfa1e16a60cf7f.pngaf44ed697cdb4c34adeb0eb7a44056e5.png8531496fed324cfdb34ae799c8d1e51b.png

int findRepeatNumber(int* nums, int numsSize){
    int temp=0,cur=0;
    while(cur<numsSize)
    {
        if(nums[nums[cur]]!=nums[cur])
        {
            temp=nums[cur];
            nums[cur]=nums[temp];
            nums[temp]=temp;
            continue;
        }
        if(cur==nums[cur])
        {
            cur++;continue;
        }
        return nums[cur];
    }
    return -1;
}


方法五:二分法(解答错误)



根据题目发现答案在[0, n-1]中, left = 0, right = n - 1, mid = (left + right) / 2,先计算整个数组中[left, mid]范围内的数的数量,如果大于


(mid - left),说明左侧有重复数字,right = mid,否则,left = mid,继续基于新的left, right二分。该种思路无法解决场景[0, 1, 2, 0, 4, 5, 6, 7, 8, 9]。

int Count(int* nums, int numsSize, int a, int b)
{
    int cnt = 0;
    int cur = 0;
    while (cur < numsSize) {
        if (nums[cur] >= a && nums[cur] <= b) {
            cnt++;
        }
        cur++;
    }
    return cnt;
}
int findRepeatNumber(int* nums, int numsSize){
    // 二分法 无法解决场景:[0, 1, 2, 0, 4, 5, 6, 7, 8, 9]
    int left = 0;
    int right = numsSize - 1;
    int mid, count;
    while (left < right - 1) {
        mid = (left + right) / 2;
        count = Count(nums, numsSize, left, mid);
        if (count > mid + 1 - left) {
            right = mid;
            continue;
        }
        left = mid;
    }
    if (Count(nums, numsSize, left, left) > 1) {
        return left;
    }
    return right;
}

097c2727bbfd4636a92fd4d09aa4f216.png


总结



感觉刷题的话还是要认真把每一题搞懂才行,看着力扣的大佬们都有很多中解法,也学习到了许多,我自己昨天才刚刚学到qsort函数,今天就用到了,加油吧!



相关文章
|
2月前
|
存储 搜索推荐 C++
剑指 Offer(第 2 版)刷题 | 03. 数组中重复的数字
本文是作者针对《剑指 Offer(第 2 版)》中 "数组中重复的数字" 问题的刷题记录,分享了使用排序算法和相邻比较大小两种方法来找出数组中的重复数字,并提供了C++的实现代码。
剑指 Offer(第 2 版)刷题 | 03. 数组中重复的数字
|
6月前
剑指 Offer 03:数组中重复的数字
剑指 Offer 03:数组中重复的数字
27 0
|
6月前
剑指 Offer 56 - II:数组中数字出现的次数 II
剑指 Offer 56 - II:数组中数字出现的次数 II
48 0
|
6月前
剑指 Offer 56 - I:数组中数字出现的次数
剑指 Offer 56 - I:数组中数字出现的次数
48 0
|
6月前
剑指 Offer 53 - I:在排序数组中查找数字 I
剑指 Offer 53 - I:在排序数组中查找数字 I
38 0
|
6月前
剑指 Offer 38:字符串的排列
剑指 Offer 38:字符串的排列
46 0
|
6月前
剑指 Offer 50:第一个只出现一次的字符
剑指 Offer 50:第一个只出现一次的字符
35 0