1题目描述:
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
2.解题思路
思路采用非暴力查找和不消耗额外空间的算法:数组重排。把原数组重新排列为一个元素和对应下标值相同的数组。该算法看起来是两层循环,但是每个数字最多进行两次交换就会找到属于自己的位置,因为总的时间复杂度还是O(n),不需要额外内存。
以{2,3,1,0,2,5,3}为例:
-
0(序号)和2(0号值)不相等,并且2(序号)和1(2号值)不相等,则交换位置,数组变为:{1,3,2,0,2,5,3};
-
0(序号)和1(0号值)仍然不相等,并且1(序号)和3(1号值)不相等,则交换位置,数组变为:{3,1,2,0,2,5,3};
-
0(序号)和3(0号值)仍然不相等,并且3(序号)和0(3号值)不相等,则交换位置,数组变为:{0,1,2,3,2,5,3};
-
0(序号)和0(0号值)相等,遍历下一个元素;
-
1(序号)和1(1号值)相等,遍历下一个元素;
-
2(序号)和2(2号值)相等,遍历下一个元素;
-
3(序号)和3(3号值)相等,遍历下一个元素;
-
4(序号)和2(4号值)不相等,但是2(序号)和2(4号值)相等,则找到了第一个重复的元素。
3.编程实现(Java):
public class duplicate_31 {
public boolean duplicate(int numbers[], int length, int[] duplication) {
if (numbers == null || length < 1)
return false;
for (int i = 0; i < length; i++) {
while (numbers[i] != i) {
if (numbers[numbers[i]] == numbers[i]) {
duplication[0] = numbers[i];
return true;
} else {
//必须先numbers[numbers[i]],如果不是,先numbers[i]会改变numbers[numbers[i]]里面的序号
int temp = numbers[numbers[i]];
numbers[numbers[i]] = numbers[i];
//将numbers[i]弄到和它序号相对应的位置
numbers[i] = temp;
}
}
}
return false;
}
}