JS演算法之找出缺失的整數
題目:一個無序陣列裡有99個不重複正整數,範圍從1到100,唯獨缺少一個整數。如何找出這個缺失的整數?
假設陣列長度是N,那麼該解法的時間複雜度是O(1),空間複雜度是O(N)。
此題有多種解法:
1、建立一個HashMap,以1到100為鍵,值都是0 。然後遍歷整個陣列,每讀到一個整數,就找到HashMap當中對應的鍵,讓其值加一。由於陣列中缺少一個整數,最終一定有99個鍵對應的值等於1, 剩下一個鍵對應的值等於0。遍歷修改後的HashMap,找到這個值為0的鍵。
[JavaScript] 純文字檢視 複製程式碼// 當前的無序陣列 var DisorderedArray = [1,2,5,3,6,4,...99] //此處省略 var HashMap = new Array(n); // 遍歷HashMap for(var i = 0; i < HashMap.length; i++){ HashMap[i] = 0; } // 遍歷無序陣列 for(var j = 0; j < DisorderedArray.length; j++){ HashMap[j] += 1; } for(var k = 0; k < HashMap.length; k++){ if(HashMap[k] === 0){ return k; break; } }
以上解法在時間上是最優的,但額外開闢了空間,如何能夠降低空間複雜度呢?
此時,便有了解法2:
先把陣列元素進行排序,然後遍歷陣列,檢查任意兩個相鄰元素數值是否是連續的。如果不連續,則中間缺少的整數就是所要尋找的;如果全都連續,則缺少的整數不是1就是100。
假設陣列長度是N,如果用時間複雜度為O(NLogN)的排序演算法進行排序,那麼該解法的時間複雜度是O(NLogN),空間複雜度是O(1)。
[JavaScript] 純文字檢視 複製程式碼// 當前的無序陣列 var DisorderedArray = [1,2,5,3,6,4,...99] //此處省略 DisorderedArray.sort(); for(var i = 1; i < DisorderedArray.length; i++){ var prev = DisorderedArray[i-1], item = DisorderedArray[i]; if(item - prev != 1){ return item-1; break; }else{ if(DisorderedArray[0] == 2){ return 1; break; } if(DisorderedArray[n] == (DisorderedArray.length-1)){ return DisorderedArray.length; break; } } }
以上解法是沒有開闢額外空間的,但是時間複雜度又大了,有辦法讓時間和空間都進一步優化麼?
此時,解法3出現:
很簡單也很高效的方法,先算出1+2+3….+100的和,然後依次減去陣列裡的元素,最後得到的差,就是唯一缺失的整數。
假設陣列長度是N,那麼該解法的時間複雜度是O(N),空間複雜度是O(1)。
[JavaScript] 純文字檢視 複製程式碼var DisorderedArray = [1,2,5,3,6,4,...99] //此處省略 var res = 0; for(var i = 1; i < 101; i++){ res += i; } for(var j = 0; j < DisorderedArray.length; j++){ res -= DisorderedArray[j] } // 最後這裡的res就是最後缺失的整數
以上解法,對於沒有重複元素的陣列,這解法在時間和空間上已經是最優了。下面開始擴充套件問題
題目擴充套件:一個無序陣列裡有若干個正整數,範圍從1到100,其中99個整數都出現了偶數次,只有一個整數出現了奇數次(比如1,1,2,2,3,3,4,5,5),如何找到這個出現奇數次的整數?
此擴充套件的題目來看,用上面的三種方法是沒有用的,在這裡,就要運用到異或運算,於是就有這了這樣的解法:遍歷整個陣列,依次做異或運算。由於異或在位運算時相同為0,不同為1,因此所有出現偶數次的整數都會相互抵消變成0,只有唯一出現奇數次的整數會被留下。
假設陣列長度是N,那麼該解法的時間複雜度是O(N),空間複雜度是O(1)。
[JavaScript] 純文字檢視 複製程式碼// js異或運算子(^) var arr = [4,4,6,8,8,2,3,3,7,6,7,1,5,9,1,5,9]; var res; for (var i = 0; i < arr.length; i++) { var flag = false; for (var j = 0; j < arr.length; j++) { if(i != j){ var aaa = arr[i] ^ arr[j]; if(!aaa) { flag = true; break; } } } if(!flag){ res = i; break; } } console.log(res) // 5 console.log(arr[res]) // 2
此處我不得不說一下上面的方法,雖然上面的程式碼解決了問題,可是還是使用了大題程式碼,這在效能上還是會有很大的損耗的。於是就有了我下面這段程式碼,依然可以得到答案,而且大減少了程式碼量
[JavaScript] 純文字檢視 複製程式碼var arr = [4,4,6,8,8,2,3,3,7,6,7,1,5,9,1,5,9]; arr.reduce((prev,next) => prev ^ next); // 此處得到結果為2 // 由於異或在位運算時相同為0,不同為1,因此所有出現偶數次的整數都會相互抵消變成0,只有唯一出現奇數次的整數會被留下
題目第二次擴充套件:一個無序陣列裡有若干個正整數,範圍從1到100,其中98個整數都出現了偶數次,只有兩個整數出現了奇數次(比如1,1,2,2,3,4,5,5),如何找到這個出現奇數次的整數?
解法:
遍歷整個陣列,依次做異或運算。由於陣列存在兩個出現奇數次的整數,所以最終異或的結果,等同於這兩個整數的異或結果。這個結果中,至少會有一個二進位制位是1(如果都是0,說明兩個數相等,和題目不符)。
舉個例子,如果最終異或的結果是5,轉換成二進位制是00000101。此時我們可以選擇任意一個是1的二進位制位來分析,比如末位。把兩個奇數次出現的整數命名為A和B,如果末位是1,說明A和B轉為二進位制的末位不同,必定其中一個整數的末位是1,另一個整數的末位是0。
根據這個結論,我們可以把原陣列按照二進位制的末位不同,分成兩部分,一部分的末位是1,一部分的末位是0。由於A和B的末位不同,所以A在其中一部分,B在其中一部分,絕不會出現A和B在同一部分,另一部分沒有的情況。
這樣一來就簡單了,我們的問題又迴歸到了上一題的情況,按照原先的異或解法,從每一部分中找出唯一的奇數次整數即可。
假設陣列長度是N,那麼該解法的時間複雜度是O(N)。把陣列分成兩部分,並不需要藉助額外儲存空間,完全可以在按二進位制位分組的同時來做異或運算,所以空間複雜度仍然是O(1)。
相關文章
- 演算法學習-第一個缺失的正整數演算法
- 如何在1到100的整數陣列上找到缺失的數字陣列
- 找出不能用列表中元素相加得到的最小整數
- 演算法41. 缺失的第一個正數演算法
- js小數轉整數JS
- 【陣列】1539. 第 k 個缺失的正整數(簡單)陣列
- js找出陣列中出現最多的元素和次數JS陣列
- C++列舉演算法之滿足條件的整數C++演算法
- Leetcode-2028. 找出缺失的觀測資料LeetCode
- 【演算法詳解】求解數值的整數次方演算法
- 找出長時序遙感影像的缺失日期並用畫素均為0的柵格填充缺失日期的檔案
- 演算法筆記01--歸納法之整數冪演算法筆記
- 缺失的數字;及找數字分析
- js面試題-找出字串中的數字,並替換為*JS面試題字串
- 給定一個整數陣列,找出總和最大的連續數列,並返回總和。陣列
- 找出一堆整數中兩個元素和為指定值的所有組合
- 每天一道演算法題系列十三之羅馬數字轉整數演算法
- 找數字續;及缺失的數字分析
- 【簡單演算法】1.兩數之和,給定整數陣列和目標值,找出陣列中2數之和等於目標值的元素演算法陣列
- DPOS 共識演算法 - 缺失的白皮書演算法
- js 將負數或小數轉成正整數JS
- js取整並保留兩位小數的方法JS
- [CodeWars][JS]如何判斷給定的數字是否整數JS
- 排序演算法-N個正整數排序排序演算法
- [CodeWars][JS]實現大整數加法JS
- 每日一道演算法:羅馬數字轉整數演算法
- 演算法學習記錄十(C++)--->數值的整數次方演算法C++
- “大整數階乖”問題的遞推演算法演算法
- js判斷指定的值是否為整數的程式碼JS
- 【演算法學習筆記】Meissel-Lehmer 演算法 (亞線性時間找出素數個數)演算法筆記
- matlab之生成不重複的隨機整數Matlab隨機
- 每日一道演算法:整數反轉演算法
- 運籌學-整數規劃IP演算法演算法
- 資料結構與演算法——有1億個整數,找出最大的1000個,要求時間越短越好,空間佔用越少越好資料結構演算法
- PHP 批鬥大會之缺失的異常PHP
- 如何應對缺失值帶來的分佈變化?探索填充缺失值的最佳插補演算法演算法
- js將小數轉換為整數程式碼例項JS
- js生成一定範圍內的隨機整數JS隨機