287. 不修改数组找出重复的数字
解题思想
题目要求不能修改输入的数组,我们可创建一个长度为n+1的辅助数组,逐一复制,我们就很容易发现哪个数字重复了。
由于需要创建一个数组,该方案需要O(N)的辅助空间。
接下来我们尝试避免使用O(n)的辅助空间。为什么数组中会出现重复数字。因为限定了范围的缘故。
好比有九个抽屉,要放十个苹果,那么必定有一个抽屉包含两个苹果。我们以限定范围有着手点,利用二分思想进行查重。
我们把1n的数字从中间数字m分为两部分。1m,m+1n。在数组nums中分别统计数字范围1m出现的次数。如果次数大于m那么重复的数字肯定在1~m之间。
利用这个限定范围的思想继续二分查找。最后终究会发现某个数字出现了两次。那么查重成功。
上述代码按照二分查找的思路。如果输入长度为n的数组,那么函数countRange奖杯调用logn次,每次需要O(n)的时间,因此总的时间复杂度是O(nlogn)。
空间复杂度为O(1)。这种算法相当于用时间换取空间。
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int start,end,mid;
start = 1;
end = nums.size()-1;
while(start<=end){
mid = (start+end)/2;
int count = countRange(nums,start,mid);
if(end == start){
if(count > 1){
return start;
}
}
if(count > (mid - start + 1)){ //寻找嫌疑
end = mid;
}else{
start = mid+1;
}
}
return 0;
}
int countRange(vector<int>& nums,int start,int end){
int count = 0;
for(int i=0;i<nums.size();i++){
if(nums[i]>=start&&nums[i]<=end){
++count;
}
}
return count;
}
};