描述:
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
例子如下:
Input:
{2, 3, 1, 0, 2, 5}
Output:
2
分析:
寻找数组中重复的数字,首先会想到的方法是遍历一遍数组,然后记录一下数组中每个元素出现的次数,若次数大于或等于2,则说明该元素重复,这是使用暴力法来求解。然而,这种情况下辅助数组的空间大量被浪费,导致空间复杂度非常高。
分析题干,得到的信息是:数组中的元素的范围是从0到n-1的,这样说明利用数组中的元素的数值作为数组下标不会出现数组越界的现象。并且并不要求找到所有的重复元素,只需要找到任意一个重复元素即可。那么,可以将数组中的每一个元素按照其数值放置到相应的下标位置,如果当某个元素出现重复时,这时该元素的数值所在的下标位置已经有了相同大小的数值,这样就可以确定重复的元素。
接下来,将示例推导一遍如下:
- [2,3,1,0,2,5]
- 将元素2,放置到数组下标为2的位置,将其与原始下标元素交换即可,得到[1,3,2,0,2,5]
- 将元素3,与数组下标为3的位置元素交换,得到[1,0,2,3,2,5]
- 同理如下,当遍历到数组下标为4时,此时发现下标2位置的元素与下标4位置的元素数值相等,说明这个元素重复
- 输出重复元素2
实现代码:
/**
这里要特别注意~返回任意重复的一个,赋值duplication[0]
*/
public static boolean duplicate(int numbers[],int length,int [] duplication) {
//判空处理
if (length<=1||numbers==null)
return false;
for (int i=0;i<length;i++){
//将值为i的元素不在为位置i上的元素开始交换
while (numbers[i]!=i){
//当数组元素的数值出现在对应的下标位置,则说明该元素重复
if (numbers[i]==numbers[numbers[i]]){
duplication[0]=numbers[i];
return true;
}
swap(numbers,i,numbers[i]);
}
}
return false;
}
private static void swap(int[] nums, int a,int b){
int t=nums[a];
nums[a]=nums[b];
nums[b]=t;
}