《剑指offer》003 数组中重复的数字

4 篇文章 0 订阅

题目:

找出数组中重复的数字。

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

示例:

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

输出:2或3

题解:

解法一:直接对数组进行排序,顺序查找直至找到重复的数并返回。时间复杂度是O(nlogn),空间复杂度为O(1),如果使用此方法一定注意询问面试官能否直接改动原数组的顺序,如果原数组的顺序不能变动,那只能将数组中的数全部复制到一个新的数组中,此时空间复杂度变为O(n)。

解法二:可以利用哈希表unordered_set来存储数据,for循环遍历数组,如果nums[i]在哈希表中没有找到,就把nums[i]插入哈希表中,如果nums[i]可以在哈希表中找到,则说明前面已经遇到过nums[i],直接返回该数即可。时间复杂度是O(n),空间复杂度是O(n)。

代码:

    int findRepeatNumber(vector<int>& nums) {
        unordered_set<int>uset;
        for(int i=0;i<nums.size();i++)
        {
            if(uset.find(nums[i])!=uset.end())
            return nums[i];
            uset.insert(nums[i]);
        }
        return 0;
    }

解法三:我们注意到题目中有一个条件:数字都在 0~n-1 的范围内。如果我们把数i放到i位置上,比如0就在0位置,1就在1位置,for循环遍历到哪个位置该位置的数就归位,如果遍历到i位置,i位置上的数是nums[i],而nums[i]位置上的数人家已经归位了,这不就找到重复的数了吗。听不懂没关系,我们还有文字解释。

在此基础上,我们可以这样做:for循环遍历数组,对于每个nums[i]如果与i相等,则继续循环,如果nums[i]与i不相等,则判断nums[i]与nums[i]位置上的数是否相等,如果相等此时就已经找到了重复的数,返回nums[i]即可,如果不相等,就交换nums[i]和nums[i]位置上的数,继续判断i位置上的数是否与i相等。听不懂没关系,我们还有例子解释。

但看文字很容易晕头撞向,我们来举个例子,数组是[2, 3, 1, 0, 2, 5, 3],从第0个位置上开始循环,首先可以看出0位置上的数据nums[0]是2,与0不相等,此时要把2放到第二个位置上去,做法就是将2和第二个位置上的数进行交换,得数组[1, 3, 2, 0, 2, 5, 3],继续观察数组,我们发现第0个位置上的数nums[0]是1,与0不相等,此时要把1放到第一个位置上去,做法就是将1和第一个位置上的数进行交换,得数组[3, 1, 2, 0, 2, 5, 3],继续观察数组,我们发现第0个位置上的数nums[0]是3,与0不相等,此时要把3放到第三个位置上去,做法就是将3和第一个位置上的数进行交换,得数组[0, 1, 2, 3, 2, 5, 3],终于!0位置上的数就是0,归位了!继续for循环发现1、2、3位置上的数都是他们自己,所以不用换位置。到第四个位置,对应的数是2,接着换吧,把2放到第二个位置上不就行了,突然发现,位置二上已经归位了,人家就是2,你看这不就重复了吗,直接返回2就好咯,这样就找到了重复的数。

时间复杂度为O(n),空间复杂度为O(1)

代码:

    int findRepeatNumber(vector<int>& nums) {
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]==i)
            continue;
            while(i!=nums[i])
            {
                int temp=nums[i];
                if(nums[temp]==temp)
                return temp;
                swap(nums[temp],nums[i]);
            }
        }
        return -1;//这里必须有返回,返回啥都行,反正有重复的数到不了这
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值