• 一起手写吧!数组去重、数组乱序!


    数组去重

    双循环去重

    双重for(或while)循环是比较笨拙的方法,它实现的原理很简单:

    先定义一个包含原始数组第一个元素的数组,然后遍历原始数组,将原始数组中的每个元素与新数组中的每个元素进行比对。

    如果不重复则添加到新数组中,最后返回新数组;因为它的时间复杂度是O(n^2),如果数组长度很大,那么将会非常耗费内存。 

    function unique(arr) {
        if (!Array.isArray(arr)) {
            console.log('type error!')
            return
        }
        let res = [arr[0]]
        for (let i = 1; i < arr.length; i++) {
            let flag = true
            for (let j = 0; j < res.length; j++) {
                if (arr[i] === res[j]) {
                    flag = false;
                    break
                }
            }
            if (flag) {
                res.push(arr[i])
            }
        }
        return res
    }

    set与解构赋值去重

     ES6中新增了数据类型set,set的一个最大的特点就是数据不重复。

    Set函数可以接受一个数组(或类数组对象)作为参数来初始化,利用该特性也能做到给数组去重。

    function unique(arr) {
        if (!Array.isArray(arr)) {
            console.log('type error!')
            return
        }
        return [...new Set(arr)]
    }

    Array.from与set去重

     Array.from方法可以将Set结构转换为数组结果,而我们知道set结果是不重复的数据集,因此能够达到去重的目的

    function unique(arr) {
        if (!Array.isArray(arr)) {
            console.log('type error!')
            return
        }
        return Array.from(new Set(arr))
    }

    数组乱序

    8在处理sort方法时,使用了插入排序和快排两种方案。 当目标数组长度小于10时,使用插入排序;反之,使用快速排序。

    其实不管用什么排序方法,大多数排序算法的时间复杂度介于O(n)到O(n²)之间, 元素之间的比较次数通常情况下要远小于n(n-1)/2。

    也就意味着有一些元素之间根本就没机会相比较(也就没有了随机交换的可能), 这些 sort 随机排序的算法自然也不能真正随机。

    其实我们想使用array.sort进行乱序,理想的方案或者说纯乱序的方案是数组中每两个元素都要进行比较, 这个比较有50%的交换位置概率。

    这样一来,总共比较次数一定为n(n-1)。 而在sort排序算法中,大多数情况都不会满足这样的条件。因而当然不是完全随机的结果了。

    Fisher–Yates

     因为这个算法是由 Ronald Fisher 和 Frank Yates 首次提出的。

    这个算法其实非常的简单,就是将数组从后向前遍历,然后将当前元素与随机位置的元素进行交换。结合图片来解释一下:

    首先我们有一个已经排好序的数组

     

    Step1: 第一步需要做的就是,从数组末尾开始,选取最后一个元素。

     

    在数组一共9个位置中,随机产生一个位置,该位置元素与最后一个元素进行交换。

     

    Step2: 上一步中,我们已经把数组末尾元素进行随机置换。 接下来,对数组倒数第二个元素动手。

    在除去已经排好的最后一个元素位置以外的8个位置中, 随机产生一个位置,该位置元素与倒数第二个元素进行交换。

    Step3: 理解了前两步,接下来就是依次进行。

     

     实现代码如下

    function shuffle(arr) {
        let m = arr.length;
        while (m > 1){
            let index = Math.floor(Math.random() * m--);
            [arr[m] , arr[index]] = [arr[index] , arr[m]]
        }
        return arr;
    }

    从表格中我们可以看出,每个元素在每个位置出现的次数相差不大,说明这种方式满足了随机性的要求。

    而且 Fisher–Yates 算法只需要通过一次遍历即可将数组随机打乱顺序,性能极为优异~~

    至此,我们找到了将数组乱序操作的最优办法:Fisher–Yates~

  • 相关阅读:
    Leetcode刷题记录--39. 组合总和
    Leetcode刷题记录--31. 下一个排列
    Leetcode刷题记录--22. 括号生成(回溯)
    Leetcode刷题记录--17. 电话号码的字母组合(回溯)
    分布式学习之--6.824MITLab1记录
    总结javascript处理异步的方法
    引用、浅拷贝及深拷贝 到 Map、Set(含对象assign、freeze方法、WeakMap、WeakSet及数组map、reduce等等方法)
    Vue之富文本tinymce爬坑录
    iOS 13 正式发布,来看看有哪些 API 变动
    Vuex,从入门到...
  • 原文地址:https://www.cnblogs.com/magicg/p/12710013.html
Copyright © 2020-2023  润新知