1. 程式人生 > 其它 >.net 遍歷陣列找重複值寫入一個新陣列_尋找陣列中的重複數字

.net 遍歷陣列找重複值寫入一個新陣列_尋找陣列中的重複數字

技術標籤:.net 遍歷陣列找重複值寫入一個新陣列delphi7儲存過程傳入陣列hdfs中與file陣列類似的陣列jquery交換陣列元素位置遍歷陣列找重複值

前言

前面一系列文章分享了資料結構與演算法的基礎知識,接下來分享一些演算法題的解題思路與實現。歡迎各位感興趣開發者閱讀。

問題描述

有一個數組,現要找出陣列中任意一個重複的元素。它的規則如下:

  1. 給定一個長度為n的陣列,陣列中每個元素的取值範圍為:0~n-1
  2. 陣列中某些數字是重複的,但是不知道哪些數字重複了,也不知道重複了幾次
  3. 求陣列中任意一個重複的數字

實現思路

這個問題的實現思路有三種:

  • 排序方法實現
  • 雜湊表輔助實現
  • 動態排序法實現

接下來,我們來一一講解下這三種實現思路。

排序方法實現

用排序方法實現分為兩步:

  1. 先用快速排序對陣列進行排序
  2. 遍歷排序好的陣列,如果其相鄰的兩個元素相等就代表陣列中有重複的數字,將其返回即可。

接下來,我們通過一個例子來驗證下上述思路。
宣告一個數組:[8, 1, 2, 3, 4, 3, 3, 4, 5]

  1. 用快速排序對上述陣列進行排序,排序好的陣列為: [1, 2, 3, 3, 3, 4, 4, 5, 8]
  2. 遍歷陣列,判斷i號位置的元素與i+1位置的元素是否相等。
    1. i = 0時,i號位置的元素為1,i+1位置的元素是2,1 !== 2,繼續下一輪遍歷
    2. i = 1時,i號位置的元素為2,i+1位置的元素是3,2 !== 3
      ,繼續下一輪遍歷
    3. i = 2時,i號位置的元素為3,i+1位置的元素是3,3 === 3,陣列中有重複數字,儲存i號位置的元素,退出迴圈。
  3. 返回找到的重複數字

時間複雜度分析:呼叫快速排序其時間複雜度為O(nlog(n)),陣列排序完成後只需遍歷陣列找到相鄰的就退出,因此總的時間複雜度為O(nlog(n))

空間複雜度分析:空間複雜度分析:由於沒有宣告新的空間,因此空間複雜度為O(1)

使用排序方法我們可以解決這個問題,但是需要對陣列進行排序,時間複雜度偏高。

雜湊表輔助實現

我們可以額外宣告一個雜湊表,然後遍歷陣列,判斷陣列中的元素是否已存在於雜湊表中,如果不存在就將其放入雜湊表中,否則就代表陣列中有重複元素,將其返回即可。

它的實現思路如下:

  1. 宣告一個空的雜湊表
  2. 從頭到尾遍歷陣列,如果當前遍歷到的元素不存在與雜湊表中,就把它加入雜湊表,否則就返回這個元素

接下來,我們通過一個例子來驗證下上述思路。
宣告一個數組:[8, 1, 2, 3, 4, 3, 3, 4, 5]

  1. 宣告一個雜湊表: const hashMap = new HashMap()
  2. 遍歷陣列,判斷陣列中的元素是否在雜湊表中。
    1. i = 0時,i號位置的元素為8,不在雜湊表中,將其放入雜湊表。
    2. i = 1時,i號位置的元素為1,不在雜湊表中,將其放入雜湊表。
    3. i = 2時,i號位置的元素為2,不在雜湊表中,將其放入雜湊表。
    4. i = 3時,i號位置的元素為3,不在雜湊表中,將其放入雜湊表。
    5. i = 4時,i號位置的元素為4,不在雜湊表中,將其放入雜湊表。
    6. i = 5時,i號位置的元素為3,在雜湊表中,儲存i號位置的元素,終止迴圈。
  3. 返回找到的重複數字

時間複雜度分析:遍歷陣列,判斷雜湊表中是否包含當前遍歷到的元素時,都可以用O(1)的時間複雜度完成,所有元素遍歷完就需要n個O(1),因此總的時間複雜度為O(n)

空間複雜度分析:由於需要一個額外的雜湊表來儲存資料,情況最壞時陣列的所有元素都會放進雜湊表中,因此總的空間複雜度為:O(n)

使用雜湊表輔助實現時,我們將時間複雜度降低了,但是代價是用了O(n)的空間儲存雜湊表,我們用空間換取了時間。

動態排序法實現

根據題意可知,陣列中元素的取值範圍在0~n-1,那麼就可以得到如下結論:

  • 如果陣列中沒有重複元素,那麼第i號元素的值一定是當前下標(i)
  • 如果陣列中有重複元素,那麼有些位置可能存在多個數字,有些位置可能沒有數字

根據上述結論,我們可以得出下述實現思路:

  1. 從頭到尾遍歷陣列,儲存第i號位置的元素,用m表示
  2. 如果m的值等於當前下標(i),則繼續遍歷。
  • 否則就判斷m的值是否等於陣列下標為m處的值。
  • 如果等於代表重複將其返回。
  • 如果不等於,就交換陣列i號位置的元素和m號位置的元素,更新m的值
  • 繼續判斷m的值是否等於陣列下標為m處的元素。

接下來,我們通過一個例子來驗證下上述思路。
宣告一個數組:[8, 1, 2, 3, 4, 3, 3, 4, 5]

  • 從頭到尾遍歷陣列,儲存i號位置的元素,用m表示。
    • 當下標為0時,m = 8。
  • 此時,m的值為8,8 != 0,陣列8號位置的元素為5,8 != 5,則交換array[0]array[8]的位置,更新m的值。交換位置後的陣列為:[5, 1, 2, 3, 4, 3, 3, 4, 8]
  • 此時,m的值為5,5 != 0,陣列5號位置的元素為3,3 != 5,則交換array[0]array[5]的位置,更新m的值。交換位置後的陣列為:[3, 1, 2, 3, 4, 5, 3, 4, 8]
  • 此時,m的值為3,3!=0,陣列3號位置的元素為3,3 === 3,元素重複,返回m。
  • 問題解決,重複數字為3。

時間複雜度分析:每個數字最多隻要交換2次就能找到它的位置,因此總的時間複雜度為O(n)

空間複雜度分析:所有操作都在原陣列進行,沒有用到額外的空間,所以空間複雜度為O(1)

使用動態排序法實現時,我們只是改變了陣列的元素順序,沒有使用額外的空間,因此空間複雜度降低了,同時時間複雜度又保持在了O(n)。所以,這種解法相對與前面兩種而言是最優的。

實現程式碼

接下來,我們來看看如何將其實現,此處我們使用TypeScript將其實現,我們先來看看如何設計這個類。
根據題意可知,並非所有陣列都能使用上面的方法來求解。因此我們在設計類的時候,要判斷呼叫者傳入的引數是否滿足題意。

  • 新建一個ts檔案,命名為:ArrayRepeatedNumber.ts
  • 建立ArrayRepeatedNumber類,宣告類內需要用到的輔助變數和建構函式。我們在建構函式中,對呼叫者傳入的引數進行校驗。
exportclassArrayRepeatedNumber{
privatesort:Sort<number>;
privatereadonlyisTrue:boolean;
constructor(privatearray:number[]){
this.isTrue=true;
//判斷引數是否滿足規則
if(array==null||array.length<=0){
this.isTrue=false;
console.log("陣列不能為空");
}
for(leti=0;iif(array[i]0||array[i]>array.length-1){
this.isTrue=false;
console.log("陣列中元素的取值範圍為0~n-1");
}
}
this.sort=newSort(array);
}
}

接下來,我們來看看上述三種實現思路的程式碼。

  • 使用排序的方法解決
getRepeatedToSort():number|void{
if(this.isTrue){
//排序陣列
constsortArray=this.sort.quickSort();
//重複的數字
letval=-1;
for(leti=0;i//排序完成後,相鄰的兩個數字相等就代表陣列中有重複數字,將其返回
if(sortArray[i]==sortArray[i+1]){
val=sortArray[i];
break;
}
}
returnval;
}
}
  • 使用雜湊表解決
getRepeatedToHashMap():number|void{
if(this.isTrue){
consthashMap=newHashMap();
letval=-1;
for(leti=0;ithis.array.length;i++){
//如果雜湊表中存在當前元素就將其返回
if(hashMap.get(this.array[i])!=null){
val=this.array[i];
break;
}
//不存在,將其加入雜湊表
hashMap.put(this.array[i],0);
}
returnval;
}
}
  • 使用動態排序法解決
getRepeated():number|void{
if(this.isTrue){
for(leti=0;ithis.array.length;i++){
//儲存陣列i號位置的元素
letm=this.array[i];
//判斷m的值是否與當前下標一樣,一樣則繼續下一輪迴圈
while(m!==i){
//判斷m的值是否等於陣列m號位置的元素
if(m===this.array[m]){
//如果相等,代表重複,返回這個元素
returnm;
}
//交換陣列的i號位置的元素和m號位置的元素
[this.array[i],this.array[m]]=[this.array[m],this.array[i]];
//交換完畢,更新m的值
m=this.array[i];
}
}
//未找到
return-1;
}
}

程式碼地址

完整程式碼,請移步:ArrayRepeatedNumber.ts

編寫測試程式碼

我們用上面舉的例子來驗證下上述程式碼是否正確執行。

constarrayRepeatedNumber=newArrayRepeatedNumber([8,1,2,3,4,3,3,4,5]);
constresult=arrayRepeatedNumber.getRepeatedToSort();
if(result!==-1&&result!=null){
console.log("ArrayRepeatedNumbertoSort:"+result);
}
79b5a5eed7d3b88235ad924deabc5ca4.png
constarrayRepeatedNumber=newArrayRepeatedNumber([8,1,2,3,4,3,3,4,5]);
constresult=arrayRepeatedNumber.getRepeatedToSort();
if(result!==-1&&result!=null){
console.log("ArrayRepeatedNumbertoHashMap:"+result);
}
12745456b6893ae5fe128efc787651aa.png
constarrayRepeatedNumber=newArrayRepeatedNumber([8,1,2,3,4,3,3,4,5]);
constresult=arrayRepeatedNumber.getRepeated();
if(result!==-1&&result!=null){
console.log("ArrayRepeatedNumber:"+result);
}
a9430a47f4e12db5afdb0207b294325a.png

寫在最後

  • 公眾號無法外鏈,文中連結可點下方閱讀原文進行檢視。