数组长度为n,数的范围{0,n-1};数组元素随机排放,可能有重复值,怎样判断是否有重复元素?下面说明一下思路,这个问题各种办法都可以解决,但是算法的复杂度和性能上却各不相同,最笨的办法就是逐个比较。
下面介绍一下我的思路:
(1)采用TreeSet对数组进行排序,排好序后计算TreeSet中元素个数,如果元素个数有变化(减少),证明重复元素没有加入,所以就可以判断元素有重复,因为TreeSetSet接口实现,底层是二叉树,保证了唯一性,重复元素不会加入到TreeSet中,但是这种会增加空间的开销。
(2)使用快排可以解决,快排的时间复杂度为O(nlogn),当然也可以有其他复杂度更好的算法来解决。快排就是选中一个基准元素,小于基准元素的往前移动,大于基准元素的往后移动,形成两个子序列,对两个子递归序列做同样的快排操作,这里采用两头逼近的办法进行快排。直到在比较的过程中发现谋一个元素与基准元素相等就可以判定有重复元素。快排采用递归容易栈溢出,而且短的序列采用快排并不比一些简单的算法效率高,所以在子序列长度在某个设定的M值内时可以采用直接插入排序或者折半插入排序等一些简单的排序算法,同样在比较的过程中如果有相等元素则可以判定数组有重复元素。下面附上Java代码供大家参考:
import java.util.Scanner;
import org.junit.Test;
public class Main8 {
/**
* 快排一趟划分过程
* @param a 要排序的数组
* @param low 子序列左边界下标
* @param high 子序列右边界下标
* @return
* 返回值不小于0,证明该趟排序没有重复元素,并且返回值就是基准元素要插入的位置,
*如果返回值为-1,证明该趟排序有重复元素
*/
public static int partition(int []a,int low,int high){
int key=a[low];
while(low<high){
while(low<high&&a[high]>=key){
if(a[high]==key){
return -1;//返回-1说明有重复元素
}
high--;
}
a[low]=a[high];
while(low<high&&a[low]<=key){
if(a[low]==key){
return -1;//返回-1说明有重复元素
}
low++;
}
a[high]=a[low];
}
a[low]=key;
return low;
}
/**
* 快排算法
* @param a 带排序数组
* @param left 待排序列左边界下标
* @param right 待排序列右边界下标
* @param flag 如果快排结束后,flag中包含true,则说明有重复元素(这里选择StringBuffer作为标志,主要是为了以引用作为形参)
*/
public static void quickSort(int [] a,int left,int right, StringBuffer flag){
if(right-left==0){//如果子序列长度等于1,结束递归,说明已经排好序
return ;
}
//基准元素下标
int middleIndex=partition(a, left, right);
if(middleIndex==-1){
flag.append("true");
return;
}
quickSort(a, left, middleIndex-1,flag);
quickSort(a, middleIndex+1, right,flag);
}
/**
* 判断数组a是否有重复元素
* @param a 待判断数组
* @return 返回true则有重复元素
*/
public boolean isDoubleOrMore(int [] a){
StringBuffer flag = new StringBuffer();
int left=0;
int right=a.length-1;
quickSort(a, left, right, flag);
if(flag.toString().contains("true")){
return true;
}
return false;
}
@Test
public void test(){
Scanner sc=new Scanner(System.in);
System.out.println("请输入数组长度");
int n=sc.nextInt();
System.out.println("请输入数组元素");
int []a=new int[n];
for (int i = 0; i < a.length; i++) {
a[i]=sc.nextInt();
}
System.out.println(isDoubleOrMore(a));
}
}
写在后面的话,由于快排这里采用的是递归,所以该算法在序列特别大的情况下可能会出现栈溢出,也就是递归过深造成的,我前几篇博客中有关于改进快排的算法,只需要在子序列长度规模在某个指定的范围内使用一些简单的排序算法就可以避免递归层级过深。