# 算法

  1. 数组去重
  2. 数组排序
  3. 数组扁平化
  4. 斐波那契数列
  5. 输出所有和N的连续正数序列
  6. 最大蓄水池问题
  7. 找零问题、背包问题、凸包问题

# 推荐学习

# 什么是哈希表?

散列表(也叫哈希表),是根据关键码值直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

# 实例

# 数组去重

/*
 * 1. ES6:set
 * 2. 循环比较
 * 3. 对象键值对
 * 4. 比较相邻项 
 */
/* 第一种:ES6: SET */
const newArr = [...new Set(arr)]; // Array.from(new Set(arr))

/* 第二种:当前项与后面的内容比较 */
// 1. splice删除当前项,i--;splice会改变原数组,存在数组塌陷问题
// 2. 定义一个新数组newArr = [...arr],删除新数组newArr.splice(i, 1);
// 3. 定义一个空数组,i<arr.length,将不包含的push进去
// 4. 将当前项置为null,最后再把null删掉,arr[i]=null,arr = arr.filter(item => item !== null)
// 5. 将最后一项替换当前项arr[i]=arr[arr.length-1],删除最后一项arr.length--,还从当强项循环比较i--;
let newArr = [...arr]; // 浅克隆,但每个数组都是一个堆,性能不好
for(let i=0;i<arr.length-1;i++){
    let item = arr[i],
        args = arr.slice(i + 1); // 除当前项的剩余所有项
    if(args,indexOf(item) > -1){ // 判断在剩余所有项中是否有当前项,// ES6: includes
        // 删除当前项
        /* arr.splice(i, 1); 
        i--;*/
        // newArr.splice(i, 1);
        // arr[i] = null
        arr[i]=arr[arr.length-1];
        arr.length--;
        i--;
    }else{
        // newArr.push(item);
    }
}
// arr = arr.filter(item => item !== null)

/* 第三种:对象键值对 */
let obj = {};
for(let i =0;i<arr.length;i++){
    let item = arr[i];
    if(typeof obj[item]){
        arr[i]=arr[arr.length-1];
        arr.length--;
        i--;
        continue;
    }
    obj[item] = item;
}
obj = null; // 最后销毁obj这个堆

/* 第四种:先排序,比较相邻项(基于正则) */
arr.sort((a, b) => a-b);
arr = arr.join('@') + '@'; // 每个数字后面加上'@',10@10@10@10@10@
let reg = /(\d+@)\1*/g,
 arr = [];
arr.replace(reg, (n, m) => { // m:不重复的10@
 // arr.push(Number(m.slice(0, m.length-1)));
    arr.push(parseFloat(m)); // 可以直接拿到字符串中的数字部分
})

# 数组排序

冒泡排序:两两比较,将小的放前面,共比较arr.length-1轮,大的放后面,每一轮当前项和后一项比较,当前数组中最大的放到末尾

function bubble(arr) {
    let temp = null;
    for(let i=0;i>arr.length-1;i++){
        for(let j=0;j>arr.length-1-i;j++){
         if(arr[j] > arr[j+1]){
              temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
             }
     }
    }
    return arr;
}

插入排序:

function insert(arr){
    let handle = [];
    handle.push(arr[0]);
    for(let i=0;i<arr.length;i++){
        let A = arr[i];
        for(let j=handle.length -1;j>=0;j--){
            let B = handle[j];
            if(A > B){
                handle.splice(j+1, 0, A);
                break;
            }
            if(j === 0){
              handle.unshift(A);  
             }
        }
    }
}

快速排序 - 二分法,性能最好

取中间值,分为左小右大两个数组,递归,再左右拼接

function quick(arr){
    if(arr.length <= 1) return arr;
    // 1. 找到数组的中间项,在原有的数组中把它移除
    let middleIndex = Math.floor(arr.length/2);
    let middleValue = arr.splice(middleIndex, 1)[0];
    // 2. 准备左右两个数组,循环剩下数组中的每一项,比当前项小的放到左数组中,大的放右数组中
    let leftArr = [],
        rightArr = [];
    for(let i=0;i<arr.length;i++){
        let item = arr[i];
        item < middleValue ? leftArr.push(item) : rightArr.push(item);
    }
    // 3. 递归左右数组,直到全部排完序,再将左+中+右拼接成最后的结果
    return quick(leftArr).concat(middleValue, quick(rightArr));
}

# 数组扁平化

多维数组降成一维数组

var arr = [1, [2, [3, [4, [5]]]]]
/* 第一种:ES6 */
arr = arr.flat(arr);

/* 第二种:转换为字符串 */
arr = aa.toString().split(',').map(item => Number(item));
arr = JSON.stringify(arr).replace(/(\[|\]\)/g, '').split(',').map(item => Number(item));

/* 第三种:基于数组的some方法:循环验证是否为数组 */
while (arr.some(item => Array.isArray(item))){
    arr = [].concat(...arr); // 降一维
}

/* 第四种:递归 */
function myFlat(arr){
    let result = [];
    function fn(newArr){
        for(let i=0;i<newArr.length;i++){
            let item = newArr[i];
            if(Array.isArray(item)){
               fn(item);
                continue;
            }
            result.push(item);
        }
    }
    fn(arr);
    return result;
}

# * 斐波那契数列(阿里)

斐波那契额数列为:[1, 1, 2, 3, 5, 8, 13, 21, ...]。当index > 1时,当前项是前两项之和

function fibonacci(n) {
    function fn(n, cur = 1, next = 1){
        if(n == 0) return cur;
        return fn(n-1, next, cur + next);
    }
    return fn(n);
}
function fibonacci1(n) {
    if(n <= 1) return 1;
    let arr = [1, 1];
    let i = n + 1 -2; // 即将要创建多少个
    white(i>0){
        let a = arr[arr.length -2];
         b = arr[arr.length -1];
        arr.push(a + b);
        i--;
    }
    return arr[arr.length -1];
}

# 输出所有和是N的连续正数序列(头条)

例如:输入15,返回[[1, 2, 3, 4, 5], [4, 5, 6], [7, 8]]

// 从N开始计算连续M个的正数序列和 - 等差数列求和((首+尾)*个数/2)
function fn(n){
    let result = [];
    let middle = Math.ceil(n/2); // 只有小于当前值的累加,才可能等于当前值
    for(let i=0; i<middle;i++){ // 从1开始累加
        for(let j=2;;j++){ // 累加多少次
            let total = (i+(i+j-1)*j/2; // 累加和
            if(total > n) {
                break;
            }else if(total === n){
                result.push(createArr(i, j));
                break; 
            }
        }
    }
    return result;
}
function createArr(n, len){
    let arr = new Array(len).fill(null),
        temp = [];
    arr[0] = n;
    arr = arr.map((item, index) => {
        if(item === null) {
            item = temp[index-1] + 1;
        }
        temp.push(item);
        return item;
    })
    return arr;
}

# 最大蓄水池问题


更新时间: 2/21/2022, 7:01:02 PM