前端需要了解的一些算法总结(持续更新)

892 阅读5分钟

首先,我们需要了解js中Array 的一些方法:

  1. splice: 数组的删除、插入、替换,会改变原数组
// 删除:开始的位置;删除的数量
[‘a’,’b’,’c’,’d’].splice(1, 2)  //[b,c]

// 插入: splice(插入的位置,0,插入的项)
[‘a’,’b’,’c’,’d’].splice(1, 0, 'e')  //[‘a’,'e',’b’,’c’,’d’]

// 替换:相当于先删除再插入
[‘a’,’b’,’c’,’d’].splice(2,2,’张三’,’李四’) //[‘a’,’b’,’张三’,’李四’]
  1. map():通过指定函数处理数组的每个元素,并返回处理后的数组
// 比如下面的将数组中的字符转为数字
['1','2','3','4'].map(function(item){
    return +item
})
// [1,2,3,4]

不会改变原数组,不会检查空数组

  1. filter:返回所有符合条件的元素组成的新数组
// 比如下面的将数组中的字符转为数字
[1,2,3,4].map(function(item){
    return item>2
})
// [3,4]
  1. every:检测数组所有元素是否都符合条件,只要有一个不符合,就返回false
[1,2,3,4].every(function(item){
    return item>2
})
// false
  1. some:检测数组所有元素是否都符合条件,只要有一个符合,就返回true
[1,2,3,4].some(function(item){
    return item>2
})
// true
  1. reduce:常用于数组累加的方法
arr.reduce(function(prev,cur,index,arr){
...
}, init);
/*
arr 表示原数组;
prev 表示上一次调用回调时的返回值,或者初始值 init;
cur 表示当前正在处理的数组元素;
index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1;
init 表示初始值
*/

常用的参数只有 prev(上次回调的返回值或者init初始值)、cur

// 累加
var arr = [3,9,4,3,6,0,9];
var sum = arr.reduce(function (prev, cur) {
    return prev + cur;
},0);
// 下面的数组扁平化:
function flatten(arr) {
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}

字符串反转

1、

var str = "abcdef"; 
console.log( str.split("").reverse().join("") );'); 
//分解
var str="abcdefg";
var a=str.split(""); //先拆分成数组
var b=str.split("").reverse(); //再反转,但还是数组
var c=str.split("").reverse().join("");//最后把数组变成字符串

2、

在这里插入图片描述

3、

在这里插入图片描述

数组去重

  1. 常用方法,依次循环数组,将不存在于新数组中的元素push到新数组中。
var array = [1, 1, '1'];

function unique(array) {
    var res = [];
    for (var i = 0, len = array.length; i < len; i++) {
        var current = array[i];
        if (res.indexOf(current) === -1) {
            res.push(current)
        }
    }
    return res;
}

console.log(unique(array));
  1. 将原数组排序后去重(判断是否与上一个元素相等,不相等就push)
var array = [1, 1, '1'];

function unique(array) {
    var res = [];
    var sortedArray = array.concat().sort();
    var seen;
    for (var i = 0, len = sortedArray.length; i < len; i++) {
        // 如果是第一个元素或者相邻的元素不相同
        if (!i || seen !== sortedArray[i]) {
            res.push(sortedArray[i])
        }
        seen = sortedArray[i];
    }
    return res;
}

console.log(unique(array));
  1. ES6 的 Set (set 类似与数组,但是成员值都是唯一的)
var array = [1, 2, 1, 1, '1'];

function unique(array) {
   return Array.from(new Set(array));
}

console.log(unique(array)); // [1, 2, "1"]

扁平化数组

扁平化:

var arr = [1, [2, [3, 4]]];
console.log(flatten(arr)) // [1, 2, 3, 4]

主要有以下几种方法:递归、toSrting、reduce、拓展运算符...

递归:

​ 于循环数组元素,如果还是一个数组,就递归调用该方法:

// 方法 1
var arr = [1, [2, [3, 4]]];

function flatten(arr) {
    var result = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]))
        }
        else {
            result.push(arr[i])
        }
    }
    return result;
}
console.log(flatten(arr))

toString:

​ 如果数组的元素都是数字,可以使用 toString 方法,因为:

[1, [2, [3, 4]]].toString() // "1,2,3,4"
// 方法2
var arr = [1, [2, [3, 4]]];

function flatten(arr) {
    return arr.toString().split(',').map(function(item){
        return +item  // split(',') 分割完之后是:['1','2','3','4'],这里的+ 用来将字符转为数字
    })
}

console.log(flatten(arr))

reduce

​ 既然是对数组进行处理,最终返回一个值,我们就可以考虑使用 reduce 来简化代码:

// 方法3
var arr = [1, [2, [3, 4]]];

function flatten(arr) {
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatten(next) : next)
    }, [])
}

console.log(flatten(arr))

...

ES6 增加了扩展运算符,用于取出参数对象的所有可遍历属性,拷贝到当前对象之中:

var arr = [1, [2, [3, 4]]];
console.log([].concat(...arr)); // [1, 2, [3, 4]]

我们用这种方法只可以扁平一层,但是顺着这个方法一直思考,我们可以写出这样的方法:

// 方法4
var arr = [1, [2, [3, 4]]];

function flatten(arr) {
	// 这里的some 判断 整个arr中是否有符合条件的就是true
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr); // 每次循环之后,arr都会扁平化一层
    }
    return arr;
}

console.log(flatten(arr))

排序

基本排序:冒泡、选择、插入 高级排序:快排、希尔排序

冒泡

每次找出剩余元素中的最大值

function bubleSort(arr){
    var len = arr.length
    for(let outer = len; outer >= 2; outer--){
        for(let inner = 0;inner <= outer - 1; inner++){
            if(arr[inner] > arr[inner + 1]){
                let temp = arr[inner]
                arr[inner] = arr[inner + 1]
                arr[inner + 1] = temp
            }
        }
    }
    renturn arr;
}
// 交换部分使用ES6 解构赋值
[arr[inner],arr[inner+1]] = [arr[inner+1],arr[inner]]

选择排序

每次将第一个元素和其他元素比较,如果小于的话交换位置,导致每次把最小的放前面

function selectSort(arr) {
    var len = arr.length;
    for(let i = 0 ;i < len - 1; i++) {
        for(let j = i ; j<len; j++) {
            if(arr[j] < arr[i]) {
                [arr[i],arr[j]] = [arr[j],arr[i]];
            }
        }
    }
    return arr
}

插入排序

每次将新的元素插入到前面的有序数组中(默认初始arr[0]是有序的)

function insertSort(arr) {
    for(let i = 1; i < arr.length; i++) {  //外循环从1开始,默认arr[0]是有序段
        for(let j = i; j > 0; j--) {  //j = i,将arr[j]依次插入有序段中
            if(arr[j] < arr[j-1]) {
                [arr[j],arr[j-1]] = [arr[j-1],arr[j]];
            } else {
                break;
            }
        }
    }
    return arr;
}

快速排序

它是一种分而治之的算法,通过递归的方式将数据依次分解为包含较小元素和较大元素的不同子序列。该算法不断重复这个步骤直至所有数据都是有序的。下面实现中,基准元素选择数组第一个元素。

function quickSort(arr) {
    if(arr.length <= 1) {
        return arr;  //递归出口
    }
    var left = [],
        right = [],
        current = arr.splice(0,1); //注意splice后,数组长度少了一个
    for(let i = 0; i < arr.length; i++) {
        if(arr[i] < current) {
            left.push(arr[i])  //放在左边
        } else {
            right.push(arr[i]) //放在右边
        }
    }
    return quickSort(left).concat(current,quickSort(right)); //递归
}

希尔:

插入排序的改良算法

排序算法 平均时间复杂度 最坏时间复杂度 空间复杂度 是否稳定
冒泡排序 O(n²) O(n²) O(1)
选择排序 O(n²) O(n²) O(1) 不是
直接插入排序 O(n²) O(n²) O(1)
快速排序 O(nlogn) O(n²) O(logn) 不是
希尔排序 O(nlogn) O(n^s) O(1) 不是

快排(一遍找元素O(n),一遍找位置O(logn))