前言:昨天看到了別人發的帖子,談到了面試題中常常出現的數組去重的問題。做爲一個熱愛學習、喜歡聽老師話的好孩紙,耳邊突然想起來高中老師的諄諄教導:不要拿到題就先看答案,要先本身思考解答,而後再對照答案檢驗。因而我便開始了獨立思考的過程:git
首先,我想到的是另建一個結果數組,用來存儲原始數組中不重複的數據。遍歷原始數組依次跟結果數組中的元素進行比較,檢測是否重複。因而乎,我寫出了以下代碼A:github
1 Array.prototype.clearRepetitionA = function(){ 2 var result = []; 3 var isRepetition; 4 for(var i=0; i<this.length; i++){ 5 isRepetition = false; 6 for(var j=0; j<result.length; j++){ 7 if(this[i] === result[j]){ 8 isRepetition = true; 9 break; 10 } 11 } 12 if(!isRepetition){ 13 result.push(this[i]); 14 } 15 } 16 return result; 17 }
寫完以後,突然想起來前幾天剛看的ECMAScript 5中的數組方法 indexOf 能夠檢索數組元素。因而我又使用 indexOf 方法替代了第二層循環,寫出了以下代碼B:面試
1 Array.prototype.clearRepetitionB = function(){ 2 var result = []; 3 for(var i=0; i<this.length; i++){ 4 if(result.indexOf(this[i]) == -1){ 5 result.push(this[i]); 6 } 7 } 8 return result; 9 }
哈,代碼一會兒從17行變成了9行了,簡潔多了。高三數學大題解法通常都不止一種的啊,而後我就繼續再想其餘方法了。indexOf 方法的意思是搜索整個數組中具備給定值的元素,返回找到的第一個元素的索引,沒有找到就返回 -1 ,第一個參數就是要搜索的值,第二個參數可選:它指定數組中的一個索引,從那裏開始搜索,若是省略這個參數,則從頭搜索。思惟一發散,想到了前面方法都是檢測值是否重複的,如今有了indexOf 方法不就能夠根據檢測到的每一個元素的第一次出現時的索引和這個元素自身的索引值比較相等來判斷是否重複嘛。因此,我又寫出了代碼C:算法
1 Array.prototype.clearRepetitionC = function(){ 2 var result = [this[0]]; 3 for(var i=1; i<this.length; i++){ 4 if(this.indexOf(this[i]) == i){ 5 result.push(this[i]); 6 } 7 } 8 return result; 9 }
寫完這個,又繼續想了想,實在是想不出其餘方法了(哎,這三個方法都是很基礎的方法,數據結構、算法沒學好,真心想不出啥驚天地、泣鬼神的牛逼方法來)。因而,我就去對照答案,檢驗本身了。一看答案,發現本身仍是真實太弱了,簡單的問題仍是有些奇思妙想的。下面不是本身想的了,就再也不說太多個人心路歷程了。廢話很少說,直接上經典的答案+解析了。數組
首先,先說一個算法中常常說的以空間換時間的解法,保持隊形,咱們就叫它代碼D吧:數據結構
1 Array.prototype.clearRepetitionD = function(){ 2 var result = []; 3 var obj = {}; 4 var key,type; 5 for(var i=0; i<this.length; i++){ 6 key = this[i]; 7 type = typeof key; 8 if(!obj[key]){ 9 obj[key] = [type]; 10 result.push(key); 11 }else if(obj[key].indexOf(type)){ 12 obj[key].push(type); 13 result.push(key); 14 } 15 } 16 return result; 17 }
這個方法中在遍歷原始數組時用一個對象 obj 的屬性來保存原始數組中元素的值。同時這個屬性的值是一個數組,用來存儲這個屬性的類型,這一點能夠把原始數組中相似數字1元素和字符串‘1’的元素區分開。這個方法經過額外構建一個對象的方式下降了上面三種方法中indexOf方法所花費的時間,能夠說較爲高效吧。學習
若是你已經知足於上面所說的以空間換時間的高效方法而不繼續看下去的話,那就大錯特錯了,好戲總在後頭嘛。如今好戲開場,毫無疑問,就是代碼E了:優化
1 Array.prototype.clearRepetitionE = function(){ 2 var result = []; 3 for(var i=0; i<this.length; i++){ 4 for(var j=i+1; j<this.length; j++){ 5 if(this[i] === this[j]){ 6 j = ++i; 7 } 8 } 9 result.push(this[i]); 10 } 11 return result; 12 }
代碼D以空間換時間,感受也就通常般。那麼代碼E呢?我擦,這代碼是錯誤的吧,這個真的能去重嗎?是的,起初我都沒看懂這代碼,看了解析後又看了一遍以後才明白過來。那麼,沒看懂的看官也要認真的看解析了:第一層從前日後遍歷原始數組,第二層循環是檢測每一個元素是否跟它以後的元素重複,若是它以後有重複元素則跳過它;若是這個元素以後全部元素都跟他不重複了,則把它添加到結果數組中。這個方法實現思路就是:獲取無重複的最右一值添加到結果數組中,這個跟第一種方法相比也優化了第二層的循環,效率要比它高,不過這個方法的結果數組中元素的順序跟原始數組中元素的順序不同了。this
看完了代碼E解析的你是否是已經伸出了大拇指、投放出了敬佩的目光呢?(這些鮮花和榮譽別給我,應該給寫這個方法的大神去)。下面再說最後一個方法:那就是先排序,再去重。老規矩,它叫代碼F:spa
1 Array.prototype.clearRepetitionF = function(){ 2 this.sort(); 3 var result = [this[0]]; 4 for(var i=1; i<this.length; i++){ 5 if(this[i] !== result[result.length-1]){ 6 result.push(this[i]); 7 } 8 } 9 return result; 10 }
這個先用數組的排序方法sort進行數組元素排序,而後再進行去重工做。這個效率真的會高嗎?哎,沒學好算法什麼的,個人答案也就三個字:不知道。若是你知道歡迎評論區告訴我。