【js版】 劍指offer【1】陣列中重複的數字
阿新 • • 發佈:2018-12-13
題目描述:
在一個長度為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; }