携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
题目描述
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
实例
输入: [1,3,4,2,2] 输出: 2
输入: [3,1,3,4,2] 输出: 3
说明
1.不能更改原数组(假设数组是只读的)。 2.只能使用额外的 O(1) 的空间。 3.时间复杂度小于 O(n2) 。 4.数组中只有一个重复的数字,但它可能不止重复出现一次
题解
首先我对这个题目的感受是很特殊,真的很特殊。你可以读出来,最后一句话降低了难度。他有很多的限制在说明里面。(千万不要觉得这不好,其实这可以提高代码能力) 我担心有些读者不理解说明的含义,我先对其进行自己的解读:
- 第一条说的很清楚了,不能改,只能读。
- O(1)这个就表示你只能定义变量,不能利用数组,哈希表等。
- 这句就是告诉你不要去想暴力求解,他的时间复杂度很高。
- 字面意思,你可以明白的。
他的题目中有句话让我觉得二分查找可能会好点(其数字都在 1 到 n 之间(包括 1 和 n))他的题目已经给你限制了数据的大小,如果没有的话,二分查找就不能使用。
那么我们开始思路的探讨 因为此题他定位了数组数据的范围,所以我们可以进行二分查找定位到那个重复的数上。 首先,我们确定中值是什么?left=1,right=n-1(n指的是数组数据的长度) mid=(left+right)/2,这就是中值。 接下来,我们确定中值之后就是要找某个数重复的次数。怎么确定呢?先举个栗子。 [1,3,4,2,2] 这样的一个数组,他的中值是2.5,我要统计比mid这个数大的个数和小的个数,很明显比mid小的数有3个,个数严格大于了他的mid,所以重复的数等于[1,2.5]区间的一个数,这样一步一步缩减,最后得出那个重复的数. 如果还不理解,那么请看下一个栗子
[2, 4, 5, 2, 3, 1, 6, 7],在这个数组中mid是4,接下来统计大于他的数和小于等于他的数的个数,分别是3个和5个,那么你就知道了重复的数在[1,3]区间里, 接下来继续,他的mid是2,重复操作,小于等于mid的数有3个严格大于mid, 接下来的mid就是1,但是小于等于他的数不能严格大于所以,以此条件,退出循环. 那么就找到了重复的数字2.
如果你懂了,你可以自己写,或者看看我的代码.
代码
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int n=nums.size();
int l=1,r=n-1,ans=-1;
while(l<=r)
{
int mid=(l+r)/2;
int cnt=0;
//cout<<mid<<endl;
for(int i=0;i<n;i++)
{
cnt=cnt+(nums[i]<=mid);
}
if(cnt<=mid)
l=mid+1;
else {
r=mid-1;
ans=mid;
}
}
return ans;
}
};