1. 程式人生 > >【js版】 劍指offer【1】陣列中重複的數字

【js版】 劍指offer【1】陣列中重複的數字

題目描述:

在一個長度為n的數組裡的所有數字都在0到n-1的範圍內。 陣列中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出陣列中任意一個重複的數字。 例如,如果輸入長度為7的陣列{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。

 可以排序後,比較前後數字是否相同來做,不過這種方法時間複雜度不行,故舍去

  由於數組裡的所有數字都在0到n-1,也就是值也在陣列的下標範圍裡。

 我們可以這樣做,通俗來講,就是把陣列中的每個值放到對應的下標的位置上。(數歸其標)

  • 從頭到尾依次掃描這個陣列中的每個數字
  • 當掃描下標為i的數字時,首先比較這個數字(用m表示)是不是等於i
  • 如果是,則接著掃描下一個數字,如果不是,則再拿它和第m個數字進行比較。
  • 如果它和第m個數字相等,就找到一個重複的數字(該數字在下標i和m的位置都出現了);
  • 如果它和第m個數字不相等,就把第i個數字和第m個數字交換,把m放到屬於它的位置
  • 重複比較交換過程,直到我們發現一個重複的數字
function duplicate(numbers, duplication)
{
    for(let i=0;i<numbers.length;i++){
        while(i!=numbers[i]){
            if(numbers[i]==numbers[numbers[i]]){
                duplication[0]=numbers[i];
                return true;
            }
           var temp = numbers[i];
           numbers[i] = numbers[temp]
           numbers[temp] = temp//交換
        }
    }
    return false;
}

這個是劍指上的做法,這種不需要額外空間,時間複雜度為O(n)

除此外,在牛客上還有種做法:

不需要額外的陣列或者hash table來儲存,題目裡寫了數組裡數字的範圍保證在0 ~ n-1 之間,所以可以利用現有陣列設定標誌,當一個數字被訪問過後,可以設定對應位上的數 + n,之後再遇到相同的數時,會發現對應位上的數已經大於等於n了,那麼直接返回這個數即可。

function duplicate(numbers, duplication)
{
    for(let i=0;i<numbers.length;i++){
        let index=numbers[i];
        if(index>=numbers.length){
            index-=numbers.length
        }
        if(numbers[index]>=numbers.length){
            duplication[0]=index;
            return true;
        }
        numbers[index]=numbers[index]+numbers.length;
    }
    return false;
}