题目
在一个长度为n的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
举例说明
例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字 2 或者 3。
题目分析
思路一:
解决这个问题的一个简单的方法是先把输入的数组排序。从排序的数组中找出重复的数字时间很容易的事情,只需要从头到尾扫描排序后的数组就可以了。排序一个长度为 n 的数组需要 O(nlogn)的时间。
思路二:
还可以利用哈希表来解决这个问题。从头到尾按顺序扫描数组的每个数,每扫描一个数字的时候,都可以用 O(1)的时间来判断哈希表里是否已经包含了该数字。如果哈希表里还没有这个数字,就把它加入到哈希表里。如果哈希表里已经存在该数字了,那么就找到一个重复的数字。这个算法的时间复杂度是 O(n),但它提高时间效率是以一个大小为 O(n)的哈希表为代价的。我们再看看有没有空间复杂度为 O(1)的算法。
/*
1. 遍历数组,采用hashmap存放每个元素,其中元素作为key存储,value为0。
2. 当前遍历元素插入hashmap时,先检查hashmap中是否已经存在同样的key。
3. 若存在,记录下该值,返回true;若不存在,存入map中,继续遍历,直到数组结束,返回false.
*/
public boolean duplicate(int numbers[],int length,int [] duplication) {
boolean flag = false;
if(numbers==null || length==0){
return flag;
}
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int num: numbers){
if(map.containsKey(num)){
flag = true;
duplication[0] = num;
break;
}
map.put(num, 0);
}
return flag;
}
根据题目描述,数组里面的值范围在0~n-1,我们可以利用布尔型的辅助数组实现数组元素查重。利用数组的值作为辅助数组的下标,当数组中存在重复的数字时,那它们就指向了同一个以该值为下标的辅助数组元素。利用这一点,在遍历访问数组的时候,每访问一个元素,将该元素值作为辅助数组元素下标,并将该辅助数组元素设置为true。当首次遍历到辅助数组元素为true的时候即找到第一个重复出现的数字。
package com.newcoder.offer;
public class Test {
public static void main(String[] args) {
int[] numbers1 = { 2, 1, 3, 1, 4 };
System.out.println(duplicate(numbers1));
int[] numbers2 = { 2, 4, 3, 1, 4 };
System.out.println(duplicate(numbers2));
int[] numbers3 = { 2, 4, 2, 1, 4 };
System.out.println(duplicate(numbers3));
int[] numbers4 = {};
System.out.println(duplicate(numbers4));
int[] numbers5 = { 2, 1, 3, 5, 4 };
System.out.println(duplicate(numbers5));
}
public static boolean duplicate(int numbers[]) {
boolean[] assist = new boolean[numbers.length];
int dulpNum = 0;
for (int i = 0; i < assist.length; i++) {
if (assist[numbers[i]] == true) {
dulpNum = numbers[i];
return true;
}
assist[numbers[i]] = true;
}
return false;
}
}