數組長度爲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));
}
}
寫在後面的話,由於快排這裏採用的是遞歸,所以該算法在序列特別大的情況下可能會出現棧溢出,也就是遞歸過深造成的,我前幾篇博客中有關於改進快排的算法,只需要在子序列長度規模在某個指定的範圍內使用一些簡單的排序算法就可以避免遞歸層級過深。