数组中的重复数字
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
剑指offer
第一种
如书上说的对数组进行排序然后遍历。
public static void main(String[] args) {
int [] array={2,3,1,0,2,5,3};
quickSort(array,0,array.length-1);
//打印
for(int i:array){
System.out.println(i);
}
Map<Integer,Integer> map=new HashMap<>();
for(int i=1;i<array.length;i++){
if(array[i]==array[i-1]){
int temp=array[i-1];
int index=i-1;
while(array[i]==temp&&i<array.length){
i++;
}
map.put(temp,i-index);
}
}
map.forEach((key, value) -> {
System.out.println(key + " : " + value);
});
}
public static void quickSort(int [] array,int start,int end){
if(array.length==0|| array==null)
return;
if(start<end) {
//枢轴点
int pivot = findPivot(array, start, end);
quickSort(array, start, pivot - 1);
quickSort(array, pivot + 1, end);
}
}
//查找枢轴点
public static int findPivot(int [] array,int start,int end){
int temp=array[start];
while(start<end){
//从后往前
while(end>start&&array[end]>=temp){
end--;
}
if(start<end){
array[start]=array[end];
}
//从前往后
while(start<end&&array[start]<=temp){
start++;
}
if(start<end){
array[end]=array[start];
}
}
array[start]=temp;
return start;
}
`
结果:
时间复杂度主要是在排序上 O(nlogn)
第二种
使用hash 表
`
public static void main(String[] args) {
int [] data={2,3,1,0,2,5,3};
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<data.length;i++){
if(map.containsKey(data[i])){
map.put(data[i],map.get(data[i])+1);
}else
map.put(data[i],1);
}
map.forEach((key,value)->{
if(value>1)
System.out.println(key+" : "+value);
});
}
`
结果:
分析 时间复杂度是O(n),空间复杂度O(n)
第三种
我感觉用自己的语言解释不清晰。
看题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。
思路:创建长度为n的数组,将数组的值存到与该值相等的指标数组下(我说的不好还是举个例子:如 data[3]=2,判断下data[2]的值是不是等于2 。如果是就说明重复了)
{2,3,1,0,2,5,3}
开始:
data[0]=2 不等于0 与 data[2]=1互换
结果:{1,3,2,0,2,5,3}
data[0]=1 不等于0 与 data[1]=3 互换
结果:{3,1,2,0,2,5,3}
data[0]=3 不等于0 与 data[3]=0 互换
结果:{0,1,2,3,2,5,3}
然后判断 data[0]=0 等于0 data[1]=1 等于1 …一直到data[4]=2
与4 不相等 看data[2]=2 与2相等 说明重复了
public static void main(String[] args) {
int [] data={2,3,1,0,2,4,4,5,4,4,3,1,2,3};
//map用来统计个数
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<data.length;i++){
//因为要统计个数我加了个条件和书上不太一样
//data[i]!=-1
while(data[i]!=i&&data[i]!=-1) {
//说明重复
if (data[data[i]] == data[i]) {
if (map.containsKey(data[i])) {
map.put(data[i], map.get(data[i])+1);
} else {
map.put(data[i], 2);
}
//因为改位置上的值为重复值,将他置为-1是为了统计重复数字出现次数
data[i] = -1;
break;
} else {
int temp = data[i];
data[i] = data[data[i]];
data[temp] = temp;
}
}
}
map.forEach((key,value)->{
System.out.println(key+" : " +value );
});
}
`
结果:
为什么要将data[i]置为-1? 是为了方便统计个数
如:{0,1,2,3,2,4} 当下标为4 即指向 2时判断2为重复数字,然后计算数组2出现次数为2,当下标移到5是即指向4,换位后{0,1,2,3,4,2},这时是不是又会多判一次2 这样2的出现次数是3了 所以错了。
这个算法时间复杂度O(n),空间复杂度比用hash表小。
说明:
剑指offer上没有说统计次数,这个是我自己加上去的要求。
会想起阿里面试官问我的问题 其实和这个有点像统计两个集合中的相同的元素?两个集合的元素都是0——n之间? 用最最优的方法统计?
那时候我说了hash 表,他好像不是很满意,现在思路就是就是讲两个集合合并成一个数组 用方法3就可以了。 加油加油!
慢慢积累吧加油加油!