數組去重-Map實現

問題由來

遇到一道面試題:找到數組中第一個非重複的數。面試

[ 1, 1, 2, 2, 3, 4, 4, 5 ]
第一個非重複的數爲 3

最簡單的想法就是兩層 for 循環遍歷數組,這樣的時間複雜度是 O(n^2)。而更高效的方式,是使用hash Map,可將時間複雜降爲O(n)數組

其實這個題目能夠衍生出三個相似的問題:數據結構

  1. 數組去重
  2. 找到數組中重複的數
  3. 找到數組中第一個非重複的數

我準備用ES6中的 Map數據結構來解決這三個問題,在這以前有必要先梳理下Map的主要知識點。函數

Map基礎梳理

JavaScript 的對象(Object),本質上是鍵值對的集合(Hash 結構),可是傳統上只能用字符串看成鍵。這給它的使用帶來了很大的限制。爲了解決這個問題,ES6 提供了 Map 數據結構。它相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。也就是說,Object 結構提供了「字符串—值」的對應,Map 結構提供了「值—值」的對應,是一種更完善的 Hash 結構實現。code

例如Map構造函數接受一個數組做爲其參數:對象

const map = new Map([
  [1, '張三'],
  [2, '李四']
]);
// 0:{1 => "張三"}
// 1:{2 => "李四"}

Map實例的屬性和操做方法:ip

  • size:返回成員總數
  • set(key, value):添加新的鍵值
  • get(key):讀取鍵對應的值
  • has(key):是否有某個鍵
  • delete(key):刪除某個鍵
  • clear():清空

Map實例的遍歷方法:字符串

  • keys():返回鍵名的遍歷器。
  • values():返回鍵值的遍歷器。
  • entries():返回鍵值對的遍歷器。
  • forEach():遍歷 Map 的全部成員。

下面來經過代碼解決三個問題:get

數組去重

去重前:[ 1, 1, 2, 2, 3, 4, 4, 5 ]
去重後:[ 1, 2, 3, 4, 5 ]

主要思路:建立一個空Map,遍歷原始數組,把數組的每個元素做爲key存到Map中,由於Map中不會出現相同的key值,因此最終獲得的Map中的全部key值就是去重後的結果。hash

function arrayNonRepeatfy(arr) {
  let hashMap = new Map();
  let result = new Array();  // 數組用於返回結果
  for (let i = 0; i < arr.length; i++) {
    if(hashMap.has(arr[i])) { // 判斷 hashMap 中是否已有該 key 值
      hashMap.set(arr[i], true);  // 後面的true 表明該 key 值在原始數組中重複了,false反之
    } else {  // 若是 hashMap 中沒有該 key 值,添加
      hashMap.set(arr[i], false);  
      result.push(arr[i]);
    }
  } 
  return result;
}

let arr = [1, 1, 1, 2, 3, 3, 4, 5, 5, "a", "b", "a"];
console.log(arrayNonRepeatfy(arr)); // [ 1, 2, 3, 4, 5, 'a', 'b' ]

上面最終產生的Map不只能夠達到去重的效果,並且對每一元素的重複性都作了標註,這樣想找到找到數組中重複的數就很方便了:

console.log(hashMap);
/*
0:{1 => true} {key: 1, value: true}
1:{2 => false} {key: 2, value: false}
2:{3 => true} {key: 3, value: true}
3:{4 => false} {key: 4, value: false}
4:{5 => true} {key: 5, value: true}
5:{"a" => true} {key: "a", value: true}
6:{"b" => false} {key: "b", value: false}
*/

找到數組中重複的數

[ 1, 1, 2, 2, 3, 4, 4, 5 ]
[ 1, 2, 4 ]
接上一節末尾,既然 hashMap中記錄了每個元素的重複狀況,找到重複的數就很簡單了,遍歷最終獲得的 hashMap,值爲 true 對應的鍵就是重複的數:
function findRepeatNumInArray(arr) {
  let hashMap = new Map();
  let result = new Array();
  for (let i = 0; i < arr.length; i++) {
    hashMap.set(arr[i], hashMap.has(arr[i]))
  }
  // 獲得 hashMap 後,對其進行遍歷,值爲 true,對應的鍵就是重複的數
  for(let [key, value] of hashMap.entries()) { 
    if(value === true) {
      result.push(key);
    }
  }
  return result; 
}

let arr = [1, 1, 1, 2, 3, 3, 4, 5, 5, "a", "b", "a"];
console.log(findRepeatNumInArray(arr));

找到數組中第一個非重複的數

[ 1, 1, 2, 2, 3, 4, 4, 5 ]
3
代碼與上一節的差很少,遍歷最終獲得的 hashMap,第一個值爲 false 對應的鍵就是第一個非重複數字:
function findFirstNonRepeat(arr) {
  let hashMap = new Map();
  for (let i = 0; i < arr.length; i++) {
    hashMap.set(arr[i], hashMap.has(arr[i]))
  }
  // 找到第一個值爲 false 的,就表明第一個非重複數,return 就行了
  for(let [key, value] of hashMap.entries()) {
    if(value === false) {
      return key;
    }
  }
  return "所有重複";
}

let arr = [1, 1, 1, 2, 3, 3, 4, 5, 5, "a", "b", "a"];
console.log(findFirstNonRepeat(arr));

總結,三類問題的核心其實就是:利用 Map 存儲每個數字的重複狀況。

相關文章
相關標籤/搜索