题目:找出数组中重复的数字
在一个长度为n的数组里的所有数字都在0到n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了, 也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2, 3, 1, 0, 2, 5, 3},那么对应的输出是重复的数字2或者3。
主要思路:数组中的数字范围为0~n-1,若没有重复数字,则排序后数字i出现在数组下标为i的位置。但是,因为有重复数字,所以数字和其下标不是一一对应的关系。重排该数组(numbers),从头到尾扫描,当扫描到下标为i时,判断其数值(m)是否等于i。若相等,则继续扫描下一位置。若不相等,则将该数值m与下标为m的数值(numbers[m])比较,若这两个数相等,则找到了第一个重复的数字(该数字在下标为i和m的位置都出现了);若不相等,则交换这两个数的位置,使得数值m 与其下标相等。接下来继续比较交换,直到找到重复的数字。
关键点:找到数值与其索引的关系。
时间复杂度:O(n)
public class DuplicateNumber
{
public static void main(String[] args)
{
int numbers[] = {2, 3, 1, 0, 2, 5, 3};
int[] duplications = new int[numbers.length];
boolean isDuplicated = duplicate(numbers, numbers.length, duplications);
if(isDuplicated)
{
System.out.println(duplications[0]);
}
}
private static boolean duplicate(int numbers[], int length, int[] duplication)
{
if (numbers == null || length <= 0) return false;
//判断输入数组是否正确
for (int i = 0; i < length; i++)
{
if (numbers[i] < 0 || numbers[i] > length - 1)
{
return false;
}
}
for (int i = 0; i < length; i++)
{
//循环直到数值和下标相等
while (numbers[i] != i)
{
int currentNumber = numbers[i];
//该数字出现两次
if (currentNumber == numbers[currentNumber])
{
duplication[0] = currentNumber;
return true;
}
//交换
int temp = numbers[currentNumber];
numbers[currentNumber] = currentNumber;
numbers[i] = temp;
}
}
return false;
}
}