题目:
找出数组中重复的数字。
在一个长度为 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;//这里必须有返回,返回啥都行,反正有重复的数到不了这
}