zoukankan      html  css  js  c++  java
  • 数组去重-Map实现

     

    原文地址:https://segmentfault.com/a/1190000015923301

     

    问题由来

    遇到一道面试题:找到数组中第一个非重复的数。

    [ 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 结构实现。

    例如Map构造函数接受一个数组作为其参数:

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

    Map实例的属性和操作方法:

    • size:返回成员总数
    • set(key, value):添加新的键值
    • get(key):读取键对应的值
    • has(key):是否有某个键
    • delete(key):删除某个键
    • clear():清空

    Map实例的遍历方法:

    • keys():返回键名的遍历器。
    • values():返回键值的遍历器。
    • entries():返回键值对的遍历器。
    • forEach():遍历 Map 的所有成员。

    下面来通过代码解决三个问题:

    数组去重

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

    主要思路:创建一个空Map,遍历原始数组,把数组的每一个元素作为key存到Map中,因为Map中不会出现相同的key值,所以最终得到的Map中的所有key值就是去重后的结果。

    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 存储每一个数字的重复情况。

  • 相关阅读:
    ETCD 添加节点报错 tocommit(2314438) is out of range [lastIndex(0)]. Was the raft log corrupted, truncated, or lost?
    如何删除docker镜像中已配置的volume
    kubeadm初始化集群
    kubeadm安装依赖镜像
    standard_init_linux.go:178: exec user process caused "no such file or directory"
    kubernetes支持local volume
    git http方式时保存密码
    分布式核心技术
    docker使用
    Python实用日期时间处理方法汇总
  • 原文地址:https://www.cnblogs.com/zxyun/p/12449922.html
Copyright © 2011-2022 走看看