【JS算法题LeetCode】含思路+详细注释,适合零基础算法小白,持续更新中......

JS算法题,LeetCode

前端JS算法题个人练习记录,含思路+详细注释,适合零基础算法小白。



提示:以下是本篇文章正文内容,下面代码可供参考

一、排序算法

01.冒泡排序

思路:相邻两两比较;每次先排出来一个最大的
平均时间复杂度:O(n^2),空间复杂度O(1)
外层循环:排好一个,即索引j减少
内层循环:i++至j
循环体:相邻两位比较大小并交换

	ArrayList.prototype.bubbleSort = function () {
   
   
        // 1.获取数组的长度
        const length = this.array.length
        // 第一次:j = length - 1,比较到倒数第一个位置
        // 第二次:j = length - 2,比较到倒数第二个位置
        for (let j = length - 1; j > 0; j--) {
   
   
            // j是外层循环的标志,j后面的都已经有序了
            for (let i = 0; i < j; i++) {
   
   
                // 升序
                if (this.array[i] > this.array[i + 1]) {
   
   
                    [this.array[i], this.array[i + 1]] = [this.array[i + 1], this.array[i]]
                }
            }
        }
    }

02.选择排序

思路:设置min标志,从后面选出最小的,和第min交换位置;每次选出最小的
平均时间复杂度:O(n^2),空间复杂度O(1)
外层循环:正常遍历j
内层循环:min+1开始
循环体:min>i,min=i

	ArrayList.prototype.selectionSort = function () {
   
   
        // 1.获取数组的长度
        const length = this.array.length
        // 2.外层循环:从0位置开始取数据,直到length-2的位置
        for (let j = 0; j < length - 1; j++) {
   
   
            // 内循环层:从i+1位置开始,和后面的数据进行比较,直至length-1
            // min用于记录最小的位置
            let min = j
            for (let i = min + 1; i < length; i++) {
   
   
                if (this.array[min] > this.array[i]) {
   
   
                    min = i
                }
            }
            // 交换min位置的数据和j位置的数据
            [this.array[min], this.array[j]] = [this.array[j], this.array[min]]
        }
    }

03.插入排序

思路:局部有序,前面挨个交换位置
平均时间复杂度:O(n^2),空间复杂度O(1)
外层循环:i从1开始,第一个默认有序
内层循环:设置temp,j=i是局部有序的零界点
循环体:只要j-1>temp,挪动j和j-1,将temp插入到该位置

	ArrayList.prototype.insertSort = function () {
   
   
        // 1.获取数组的长度
        let length = this.array.length
        // 2.外层循环:从第1个位置开始获取数据,像前面局部有序进行插入
        for (let i = 1; i < length; i++) {
   
   
            // 3.内层循环:获取i位置的元素,和前面的数据依次进行比较
            // i和j是局部有序的临界点
            let temp = this.array[i]
            let j = i
            // 前面局部有序的值>temp,则进行交换,再j--向前挪一位
            while (this.array[j - 1] > temp && j > 0) {
   
   
                this.array[j] = this.array[j - 1]
                j--
            }
            // 4.将j位置的数据,放置temp即可
            this.array[j] = temp
        }
    }

04.希尔排序

思路:隔个gap,插入排序,然后缩小gap差距
平均时间复杂度:O(n^(1.3-2)),空间复杂度O(1)
最外层循环:gap>=1,gap向下取整除2
外层循环:i从gap开始,第一个默认有序
内层循环:设置temp,j=i是局部有序的零界点
循环体:只要j-gap>temp,挪动j和j-gap,将temp插入到该位置

	ArrayList.prototype.shellSort = function () {
   
   
        // 1.获取数组的长度
        let length = this.array.length
        // 2. 初始化增量gap
        let gap = Math.floor(length / 2)
        // 3. while循环,gap不断减小
        while (gap >= 1) {
   
   
            // 4. 以gap作为间隔,进行分组,对分组进行插入排序
            // 从第gap个位置开始获取数据,像前面的第一个局部有序进行插入
            for (let i = gap; i < length; i++) {
   
   
                let temp = this.array[i]
                let j = i
                while (j > gap - 1 && this.array[j - gap] > temp) {
   
   
                    this.array[j] = this.array[j - gap]
                    j -= gap
                }
                // 5. 将j位置的元素赋值temp
                this.array[j] = temp
            }
            gap = Math.floor(gap / 2)
        }
    }

05.快速排序

思路:递归,双指针。在冒泡排序基础上使用分治思想
只要i<j, j i i j
右边比基数大,j–;比基数小则交换
左边比基数小,i++;比基数大则交换
将pivot放到正确的位置(一趟找到该值所在的正确位置),再分治两侧递归

	function quickSort(arr, left = 0, right = arr.length - 1) {
   
   
    // 递归条件,left < right
    if (left < right) {
   
   
        // 基准值
        let pivot = arr[left];
        // 左右指针
        let i = left;
        let j = right;
        while (i < j) {
   
   
            // 右边比基数大,j--
            while (i < j && arr[j] > pivot) {
   
    j--}
            // 遇到比基数小,交换
            arr[i] = arr[j];
            // 左边比基数小,i++
            while (i < j && arr[i] < pivot) {
   
    i++}
            // 遇到比基数大,交换
            arr[j] = arr[i];
        }
        //此时i与j位置一致,将pivot放在此位置即可
        arr[i] = pivot;
        // 对基数左边递归
        quickSort(arr, left, i - 1);
        // 对基数右边递归
        quickSort(arr, i + 1, right);
    // 递归终止条件,left >= right
    } else {
   
   
        return;
    }
    // 返回数组
    return arr
}

二、JS手写题

01.Object.create

// 1.手写Object.create
// 返回一个Obj的实例obj,即实例obj的proto指向Obj的prototype
// 例:Object.create(null),创建了一个没有原型的对象
function create(Obj) {
   
   
    // 1.创建空的构造函数 2.F的prototype指向Obj 3.new一个F的实例并返回
    function F() {
   
    }
    F.prototype = Obj
    return new F()
}
// 测试用例
const nullObj = _create(null)
console.log(nullObj);

02.instanceof

// 2.手写instanceof方法
// 使用方法:[] instanceof Array
// left是实例,right是构造函数类
function myInstanceof(left, Right) {
   
   
    let proto = Object.getPrototypeOf(left)
    let prototype = Right.prototype
    while (true) {
   
   
        if (proto === null) return false
        if (proto === prototype) return true
        // 注意此处不能let重复声明
        proto = Object.getPrototypeOf(proto)
    }
}
// 测试用例
const arr2 = []
console.log(myInstanceof(arr2, Array))

03.new

// 3.手写new
// new一个构造函数,会创建一个实例对象,该实例对象具有构造函数的内置对象(构造器属性)以及原型上的属性
// 隐性的步骤
//将构造函数中的构造属性赋予this
// this.name = name;
function _new() {
   
   
    // 1.创建空对象;2.获取constructor构造函数(arguments的第一个参数);
    // 3.obj指向构造函数的原型;4.执行构造函数,this指向obj;5.构造函数如果返回对象,直接返回该对象
    let obj = {
   
   }
    // 利用数组shift方法,将arguments的第一个参数,构造函数提出来
    let constructor = Array.prototype.shift.call(arguments)
    obj = Object.create(constructor.prototype)
    // 剩余arguments是数组,使用apply方法
    let result = constructor.apply(obj, arguments)
    // result是构造函数返回的,若是对象,则直接result返回
    return (result !== null && (typeof result === 'object')) ? result : obj
}
// 测试用例
function Person(name, age) {
   
   
    this.name = name
    this.age = age
    return {
   
   
        name: '张三',
        age: 18
    }
}
console.log(_new(Person, 'Hugh', 24))

06.PromiseAll

function promiseAll(promises) {
   
   
    // 返回Promise实例
    return new Promise((resolve, reject) => {
   
   
        // 判断参数类型
        if (!Array.isArray(promises)) {
   
   
            throw new Error('参数类型应为数组')
        }
        // 结果数组,长度,成功的计数
        const result = []
        const nums = promises.length
        let count = 0
        // 遍历
        for (let i = 0; i < nums; i++) {
   
   
            // 处理每个promise
            Promise.resolve(promises[i]).then(
                // 成功的逻辑
                value => {
   
   
                    count++
                    result[i] = value
                    if (count == nums) {
   
   
                        // 返回结果数组
                        return resolve(result)
                    }
                    // 失败的逻辑
                }, error => {
   
   
                    reject(error)
                }
            )
        }
    })
}
// 测试用例
let p1 = new Promise((resolve, reject) => {
   
   
    setTimeout(() => {
   
   
        resolve(1)
    }, 1000)
})
let p2 = new Promise((resolve, reject) => {
   
   
    setTimeout(() => {
   
   
        resolve(2)
    }, 2000)
})
promiseAll([p1, p2]).then(res => {
   
   
    console.log(res);
}).catch(err => {
   
   
    console.log(err);
})

07.Promise.race

// 7.手写promise.race
Promise.race = function (promises) {
   
   
    return new Promise((resolve, reject) => {
   
   
        for (let i = 0; i < promises.length; i++) {
   
   
            promises[i].then(resolve, reject)
        }
    })
}

// 测试用例
let p1 = new Promise((resolve, reject) => {
   
   
    setTimeout(() => {
   
   
        resolve(1)
    }, 1000)
})
let p2 = new Promise((resolve, reject) => {
   
   
    setTimeout(() => {
   
   
        resolve(2)
    }, 2000)
})
Promise.race([p1, p2]).then(res => {
   
   
    console.log(res);
}).catch(err => {
   
   
    console.log(err);
})

08.debounce

function debounce(fn, wait) {
   
   
    let timer = null

    return function () {
   
   
        let context = this
        let args = arguments

        if (timer) {
   
   
            clearTimeout(timer)
            timer = null
        }
        timer = setTimeout(() => {
   
   
            fn.apply(context, args)
        }, wait)
    }
}

09.throttle

// 时间戳,使用这一方法,会立即执行
function throttle(fn, delay) {
   
   
    let currTime = Date.now()

    return function () {
   
   
        let context = this
        let args = arguments
        let nowTime = Date.now()

        if (nowTime - currTime > delay) {
   
   
            fn.apply(context, args)
            currTime = Date.now()
        }
    }
}
// 定时器实现,不会立即执行,但会在最后一次停止触发后再执行一次
function throttle2(fn, wait) {
   
   
    let timer = null;
    return function () {
   
   
        let context = this;
        let args = arguments;
        // 若没有定时器,说明上一次设定的定时器已到时销毁
        if (!timer) {
   
   
            timer = setTimeout(function () {
   
   
                fn.apply(context, args);
                timer = null;
            }, wait)
        }
    }
}

10.判断类型

function getType(value) {
   
   
    //如果时null值
    if (value === null) return value + ""

    //如果是引用类型
    if (typeof value === "object") {
   
   
        let valueClass = Object.prototype.toString.call(value)
        console.log(valueClass); // "[object Object]"  "[object Array]"
        let type = valueClass.split(" ")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值