以下为代码实现:
package com.example.offer;
import java.util.HashMap;
/**
* 在一个长度为n的数组里的所有数字都在0-n-1的范围内。数组中某些数字是重复的,
* 但是不知道有几个数字重复了,也不知道每个数字重复了多少次。
* 找出数组中任意重复的数字
*/
public class DuplicateTest {
public static void main(String[] args) {
//int[] array=null; //测试空指针的情况
int[] array={2,3,1,0,2,5,3};
int result03=duplicateNum03(array);
//int result02=duplicateNum02(array);
//int result=duplicateNum(array);
if(result03>=0){
System.out.println("数组中重复的数字为:"+result03);
}else{
System.out.println("数组中不存在重复的数字");
}
}
/**
* 第一种方法,将数组进行排序,排序之后找到重复的数
* @param array
* @return
*/
public static int duplicateNum(int[] array){
//避免空指针
if(array==null || array.length<=0){
throw new NullPointerException("您输入的数组为空");
}
//避免输入的数组元素不符合要求
for (int i = 0; i < array.length; i++) {
if(array[i]<0 || array[i]>array.length-1){
throw new IllegalArgumentException("您输入的数组不符合要求");
}
}
int result=-1;
//采用冒泡排序
for (int i = 0; i < array.length-1; i++) {
//优化:如果一轮遍历下来,没有进行任何的交换,说明数组的顺序已经排好了
boolean flag=true;
for (int j = 0; j < array.length-i-1; j++) {
if (array[j]>array[j+1]){
int temp=0;
temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
flag=false;
}
}
if(flag){
break;
}
}
//打印一下数组
for (int num :array) {
System.out.print(num+" ");
}
//查询出重复的数字
for (int i = 0; i < array.length; i++) {
if(array[i]==array[i+1]){
result=array[i];
break;
}
}
return result;
}
/**
* 第二种方法:采用hash表解决
* @param array
* @return
*/
public static int duplicateNum02(int[] array){
//避免空指针
if(array==null || array.length<=0){
throw new NullPointerException("您输入的数组为空");
}
//避免输入的数组元素不符合要求
for (int i = 0; i < array.length; i++) {
if(array[i]<0 || array[i]>array.length-1){
throw new IllegalArgumentException("您输入的数组不符合要求");
}
}
int result=-1;
//采用hashMap实现
HashMap<Integer,Integer> map=new HashMap();
for (int i = 0; i < array.length; i++) {
if(map.containsValue(array[i])){
result=array[i];
break;
}else{
map.put(array[i],array[i]);
}
}
return result;
}
/**
* 第三种方法:利用数组中的数字在0-n-1之间这个特性
* 遍历这个数组,首先比较当前这个数值是否与其下标相等,如果相等则扫描下一数值
* 如果不相等则将此数值与以此数值为下标数值进行比较,如果相等则找到相等的数字
* 如果不相等则将两个数值进行交换
* @param array
* @return
*/
public static int duplicateNum03(int[] array){
//避免空指针
if(array==null || array.length<=0){
throw new NullPointerException("您输入的数组为空");
}
//避免输入的数组元素不符合要求
for (int i = 0; i < array.length; i++) {
if(array[i]<0 || array[i]>array.length-1){
throw new IllegalArgumentException("您输入的数组不符合要求");
}
}
int result=-1;
for (int i = 0; i < array.length ; i++) {
System.out.println("每次都打印出i值:"+i);
while (array[i]!=i){
if(array[i]==array[array[i]]){
result=array[i];
return result;
}else{
//交换两个值
int temp=0;
temp=array[array[i]];
array[array[i]]=array[i];
array[i]=temp;
}
}
}
return result;
}
}
代码分析:第一种方法采用排序,时间复杂度为O(n2);第二种方法采用Hash表,我直接使用了HashMap,但是使用HashMap应该要考虑很多的底层性能问题,所以可以自己根据数组的长度模拟一个哈希表,所以第二种的时间复杂度是O(n),另外空间复杂度是O(n)。第三种,看代码的话是用到了两层循环,会认为时间复杂度为O(n2),但是每个数字最多只要交换两次就可以找到属于他的位置,所以总的时间复杂度是O(n), 空间复杂度为O(1)。