Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array, but it could be repeated more than once.
思路:在一个有n+1个元素的数组中包含的数字是在1-n的范围内。根据抽屉原理,至少有一个数字是会出现重复的。题目限定在数组中只有一个元素重复。题目相当于在n+1个空位上放上大小在1到n的数字。
算法的要求:
(1)不得修改数组。这样的话就不能通过给数组排序,然后找到相邻的数字相等的方式来找到出现两次的元素
(2)只能使用o(1)的空间。也就是不能通过map来存下每个元素对应的个数,最后找到那个个数等于二的元素这种方式
(3)要求算法的时间负责度小于o (n*n),则就不能通过针对每一个元素,遍历数组查看有没有重复的方式
解决方式:可以使用抽屉原理。设置start=0,end=nums.size()-1 ,则此时有n个位置,放置的元素在0~nums.size()-2之间。计算下标mid=(start+end)/2的大小是多少,然后统计在nums中小于mid的个数times。理论上如果不出现重复的话,在这个数组中小于mid的数字个数应该小于mid。此时如果统计的times>mid,则出现重复的数字的大小在0-mid之间,这个时候修改end=mid-1,计算数组的前一半。否则当mid>times的时候,则说明必有大于mid的数字出现了重复,则考虑数组的后一半即可,此时修改start=mid+1。由于题目要求必定含有重复的数字,就不考虑mid=times的情况了
class Solution {
public:
int findDuplicate(vector<int>& nums) {
//抽屉原理
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int mid=(left+right)/2;
int times=0;
for(int i=0;i<nums.size();i++)
if(nums[i]<=mid)
times++;
if(times>mid)
right=mid-1;
else
left=mid+1;
}
return left;
}
};
使用hash的方式在leetcode上也能过,代码如下
class Solution {
public:
int findDuplicate(vector<int>& nums) {
unordered_map<int,bool>res;
int slo=INT_MIN;
for(int i=0;i<nums.size();i++)
{
if(res.find(nums[i])!=res.end())
{
slo=nums[i];
break;
}
else
res[nums[i]]=true;
}
return slo;
}
};