数组中找出任意重复元素
在0—n-1个数中找出出现次数大于一的任意一个元素
有两种做法
修改原数组进行查找
数据样例:2, 3, 2, 0, 2, 5, 3
数据索引:0, 1 ,2, 3, 4, 5, 6
因为给定范围0~n-1,如果有重复,肯定有元素放在它所在值的索引上之后,还有与它值相同的元素跟自己的索引值对不上,样例中如果把2放到no.2处,no.0处的2和0就对不上,导致回到原位(值与下标相同)但是还有一个值在别的位置上,导致那个位置找不到与自己index所匹配的值。
所以我们要将每个index上的值都要换回属于他自己的位置,直到换回后,如果此时该index的值不与index相等,代表这个值就是重复的那个值。
class Solution {
public int duplicateInArray(int[] nums) {
for(int i = 0;i < nums.length;i++){
if(nums[i] < 0 || nums[i] > nums.length - 1)return -1;
}
for(int i = 0;i < nums.length;i++){
while(nums[i] != nums[nums[i]]){
int a = nums[i];
int b = nums[nums[i]];
nums[i] = b;
nums[a] = a;
}
if(nums[i]!= i)return nums[i];
}
return -1;
}
}
不修改数组的方法
分析:
如果不修改数组,只能拿另外一个数组作为比对,用二分查找的思想来处理
比如 1 2 2 2 4 5
数组索引 0 1 2 3 4 5
先从中间劈开
有0 1 2 3
设一个计数器count
从原数据里一个一个跟0 1 2 3 比,出现了就加一
1 出现了 count = 1
2 出现了 count = 2
2 出现了 count = 3
2 出现了 count = 4
4 没出现 count = 4
5 没出现 count = 5
5 比 0 1 2 3(mid-start+1)的个数要大所以代表前四个数里肯定有重复的
如果原数据是1 2 3 4 5 6你拿这种方法去比
没有重复数据,得出的count不会大于索引的个数
然后以count是否大于二分后数组的个数一直分分到start==end为止
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int l = 1,r = nums.size() - 1;
while(l < r){
int mid = l + r >> 1;
int s = 0;
for(auto x : nums)s += x >= l && x <= mid;
if(s > mid - l + 1) r = mid;
else l = mid + 1;
}
return r;
}
};