/**
* 虽然是两重循环,但每个数字至多只要交换两次就能找到属于自己的位置,因此 时间复杂度是O(n),
* 所有的操作步骤在原数组进行,因此 空间复杂度为O(1)
*/
public boolean duplicate(int numbers[], int length, int[] duplication) {
int temp;
if (length <= 1)
return false;
for (int i = 0; i < length; i++) {
while (numbers[i] != i) {
if (numbers[numbers[i]] != numbers[i]) {
temp = numbers[numbers[i]];
numbers[numbers[i]] = numbers[i];
numbers[i] = temp;
} else {
// 找到了重复元素
duplication[0] = numbers[i];
return true;
}
}
}
return false;
}
2、不修改数组找出重复的数字
在一个长度为n+1的数组里面的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。
请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为9的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。
解法一:借助长度为n+1的辅助数组。时间复杂度:O(n),空间复杂度:O(n)
解法二:
以时间换空间,取数组取值范围的中间值,
如当n=7时,数组长度为8,数字范围为【1,7】,取到中间数值为4,再遍历数组,计算在【1,4】范围内的数值个数,如果大于4,则该范围内必有重复值,如果小于等于4,则【5,7】的范围内必有重复值。
以二分法的思想确定下一个必有重复值的数组范围,直至取值范围区间长度为,若存在重复数字,则输出。
public static void main(String[] args) {
int[] array = {2, 3, 5, 4, 3, 2, 6, 7};
int start = 1, end = array.length - 1;
while (start <= end) {
//取中
int middle = ((end - start) >> 1) + start;
int count = getCount(array, start, middle);
if (start == end) {
if (count > 1) {
//输出重复数字
System.out.println(start);
break;
} else {
break;
}
}
if (count > (middle - start + 1)) {
end = middle;
} else {
start = middle + 1;
}
}
}
//查找数组中值位于start和end之间的元素个数
public static int getCount(int[] array, int start, int end) {
if (array == null)
return 0;
int count = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] >= start && array[i] <= end) {
count++;
}
}
return count;
}