JS面试常见编程题

时间复杂度:

事后统计法 console.time('AAA')  console.timeEnd('AAA) 跟电脑的运行环境和配置有关系

事情预估法 O

  • O(1)如果算法执行的时间不随着问题n的增长而增长,即使算法中有上千条,语句,执行的时间也不过时一个较大的常数     (赋值等操作,不需要计算)
  • O(log2(n))当数据增大n倍时耗时增大log(n)倍(这里的log是以2为底的,比如当数据增大256倍时,耗时这增大八倍)    (fpr循环每次i*=2)
  • O(n):数据量增大几倍,耗时也增大几倍    ( for循环)
  • O(n^2)数据增大n倍时,耗时也增大n的平分倍  (双for循环)
  • O(2^n) 2^10=1024

1.截取url问号参数

let url = 'http://www.xxxxxx.cn/?lx=1&name=js&form=baidu'
const toObj = function toObj(str) {
    let obj = {},
        qusindex,
        parm,
        item
    //获取问哈首次出现的位置
    qusindex = str.indexOf("?")
    //截取问号后面的字符串,将字符根据&分割为数组
    parm = str.slice(qusindex + 1).split('&');
    for (let i = 0; i < parm.length; i++) {
        //数组每一项是字符串在等号拆分
        item = parm[i].split("=")
        //属性名=属性值
        obj[item[0]] = item[1]
    }
    return obj
}



console.log(toObj(url));

2.对无序数组Array(n),查找第k大元素

// Input: let arr[] = {8, 15, 6, 3, 20, 25}  k = 3  // Output: 8

const computed = (arr, k) => {
    //排序
    let newArr = arr.sort((a, b) => a - b);
    console.log(newArr);
    //k是索引 k如果小于1那就是第一位,大于数组长度就是最后一位 否则就是k
    k = k < 1 ? 1 : (k > arr.length ? arr.length : k);
    //索引从0开始记得减一
    return arr[k - 1];
};
console.log(computed(arr, 3));

3.数组扁平化

第一种


    let arr = [1, 2, [3, 4], [5, [7, 8]]]
    const flatten = function flatten(arr) {
        let rueslt = [];
        for (let i = 0; i < arr.length; i++) {
             //如果是一个数组那就在执行函数传递数组的每一项,拼接数组
            if (Array.isArray(arr[i])) {
                rueslt = rueslt.concat(flatten(arr[i]))
            } else {
             //不是数组就追加到新数组中
                rueslt.push((arr[i]))
            }

        }

        return rueslt
    }
    console.log(flatten(arr));

第二种

  //转字符串 字符串方法,号分割为数组 ,在循环数组每一项,把数组的每一项强制转数组
    let arr = [1, 2, [3, 4], [5, [7, 8]]]
    const flatten = function flatten(value) {
        return value.toString().split(',').map((item => {
            return Number(item)
        }))
    }
    let newArr = flatten(arr)
    console.log(newArr);

第三种

    let arr = [1, 2, [3, 4], [5, [7, 8]]]
    const newArr = arr.flat(Infinity)
    console.log(newArr);

4.数组去重

第一种

拿出当前项和后面的内容做比较

    let ary = [1, 1, 2, 2, 3, 3, 4, 4]
    //拿出当前项和后面的内容做比较
    for (let i = 0; i < ary.length - 1; i++) {
        let item = ary[i],
            args = ary.slice(i + 1);
        if (args.indexOf(item) > -1) {
            //包含:可以把当前项干掉
            //splice删除数组会对原数组发送改变,会有数组塌陷问题
            ary.splice(i, 1);
            i--;
        }
    }
    console.log(ary);

第二种

拿出数组中的每一项,向新容器中存储,如果已经存储过了,把当前项干点

    let ary = [1, 1, 2, 2, 3, 3, 4, 4]
    //拿出数组中的每一项,向新容器中存储,如果已经存储过了,把当前项干点
    let obj = {};
    for (let i = 0; i < ary.length; i++) {
        let item = ary[i];
         //属性名不等于undefined就是存在
        if (typeof obj[item] !== "undefined") {
            ary[i] = ary[ary.length - 1];
            ary.length--;
            i--;
        }
        obj[item] = item;
    }
    console.log(ary);

第三种

  let ary = [1, 1, 2, 2, 3, 3, 4, 4]
    let newAry = Array.from(new Set(ary))

    console.log(newAry);

5.冒泡排序

从小到大排序,拿当前项和数组后一项做比较,如果当前项比后一项大,就交换位置,一轮结束后最大值在最后面

  • 一共需要比较多少轮:数组长度-1,
  • 每一轮比较多少次:最多数组长度-1次(不用和自己比),还要把之前放到末尾的值排除掉
  • 两者交换位置1. c=a ,a=b, b=c   2. [a,b]=[b,a]   3.a=a+b b=a-b a=a-b
  let ary = [12, 8, 24, 16, 1]
    //实现数组中两项(索引j/i)的交换
    function swap(arr, i, j) {
        let temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        return arr;
    }
    Array.prototype.bubble = function bubble() {
        //this是处理的数组
        let _this = this,
            flag = false;
        //控制循环多少轮
        for (let i = 0; i < _this.length - 1; i++) {
            //每轮循环多少次
            for (let j = 0; j < _this.length - 1 - i; j++) {
                //交换位置
                if (_this[j] > _this[j + 1]) {
                    swap(_this, j, j + 1);
                    //还没有排好
                    flag = true;
                };
            };

            if (!flag) break;
            flag = false;
        }
        return _this;
    }
    ary.bubble()
    console.log(ary);

6.插入排序

手里先抓一张牌,一依次从桌面取牌,每次取出一张牌,都和手里的牌进行比较

  • 如果新取来牌 比当前这张大(我就放到当前这张的后面){倒着比较}
  • 如果比当前这张牌要小,继续往前比,值到遇到比他大的
  • 如果比较到头,没有比新抓的牌要小的,我们放到最开始的位置即可

    Array.prototype.insert = function insert() {
        //先取出一张牌放到手里
        let _this = this,
            hanlde = [];
        hanlde.push(_this[0]);
        //开始抓牌
        for (let i = 1; i < _this.length; i++) {
            //每次新抓的牌
            let A = _this[i];
            //和手里的牌依次比较(倒着比较)
            for (let j = hanlde.length - 1; j >= 0; j--) {
                //要比较的手里的这张牌
                let B = hanlde[j];
                //新抓的牌A比B更大,则放在B的后面
                if (A > B) {
                    //从j开始删除0个插入到J的后面
                    hanlde.splice(j + 1, 0, A)
                    break;//没必要和手里的牌在比较
                };
                //都比到最开始,A都没有比任何牌大,则A是最小的,插入到最开始
                if (j === 0) {
                    hanlde.unshift(A)
                }
            }
        }
        return hanlde
    }
    let arr = [12, 8, 24, 16, 1];
    arr = arr.insert();
    console.log(arr);

7. 快速排序

二分法:

  • 拿出数组中的中间项 向下取整Math.floor()
  • 拿每一项和中间项做比较,比中间项小的放左边,比中间项大的放右边
  • 在依次把左边和右边的同样方式处理,直到某一边的数组一项都没有,则不在拆分
  • 最后的结果每一次都是把左边+中间+右边
    Array.prototype.quick = function quick() {
        let _this = this;
        //如果传递的数组只有一项无需处理
        if (_this.length <= 0) {
            return _this;
        }
        //获取中间项,并且把中间项在数组中删除
        let middleIndex = Math.floor(_this.length / 2),
            //返回项是数组[0],取出值
            middleValue = _this.splice(middleIndex, 1)[0];
        let arrLeft = [],
            arrRight = [];
        for (let i = 0; i < _this.length; i++) {
            let item = _this[i];
            item < middleValue ? arrLeft.push(item) : arrRight.push(item);
        }
        return quick.call(arrLeft).concat(middleValue, quick.call(arrRight));
    };
    let arr = [12, 8, 24, 16, 1];
    arr = arr.quick();
    console.log(arr);

8.斐波那契序列

实现[1,1,2,3,5,3,8,13,21,....]函数 function(0)--->1 function(4)-->5

 function fibonacci(n) {
        if (n <= 1) return 1;
        let arr = [1, 1]
        //n是索引,即将要创建多少个
        let i = n + 1 - 2;
        while (i > 0) {
            let a = arr[arr.length - 2],//倒数第二项
                b = arr[arr.length - 1];//倒数第一项
            arr.push(a + b)
            i--;
        }
        return arr[arr.length - 1];
    }
    console.log(fibonacci(5));

9.输入一个整数N,输出所有和为N的连续正数序列

  • 例如 ;输入15  结果[1,2,3,4,5],[4,5,6],[7,8]
  • 15=>15/2向上取整 8, 只取中间值以下的
  • 从N开始计算连续M个的正数序列和
    function createdArr(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;
    }
    function fn(count) {
        let result = [];
        //取出中间值
        let middle = Math.ceil(count / 2);
        //从1开始累加
        for (let i = 1; i <= middle; i++) {
            //控制累加多少次
            for (let j = 2; ; j++) {
                let total = (i + (i + j - 1)) * (j / 2)
                if (total > count) {
                    break
                } else if (total === count) {
                    result.push(createdArr(i, j))
                }
            }
        }
        return result
    }
    console.log(fn(15));

 10.查找重复数字

实现一个方法sameNumbers找出同时存在于两个数组中的所有数字

处理异常:为传入arr1或者arr2.或者其中一项不是数组

字符串格式的数字需要转为数字,返回结果过滤所有非数字项

  // Number.isFinite如果是有限数字返回 true,否则返回 false。
    function SomeNumbers(arr1, arr2) {

        //检测是不是两个参数
        if (!(arr1 && arr2)) {
            console.log("请传入两个参数哦~~");
            return;
        };
        if (!(Array.isArray(arr1) && Array.isArray(arr2))) {
            console.log('请确认传入的是数组哦~~');
        };
        arr1.map(item => {
            return Number(item)
        });
        arr2.map(item => {
            return Number(item)
        });

        let newArr = [];
        for (let i = 0; i < arr1.length; i++) {
            if (arr2.indexOf(arr1[i]) > -1) {
                if (Number.isFinite(arr1[i])) {
                    newArr.push(arr1[i])
                }
            }
        }

        return newArr
    };
    console.log(SomeNumbers([1, 5, 6], [2, 6, 7]));

 11.拼接URL

  slice,substring,substr 都是用来截取字符串或数组的,然而数组只能使用slice,这三者如果不传参数,则都返回全部内容;

  • substring,slice含头不含尾
  • substring不支持负数索引,
  • substr是从x开始截取y 个
   let url = "http://www.xxxx.com";
        let obj = {
            name: "lisa",
            age: 18,
            lx: 1,
            form: 'http://www.baidu.com'
        };
        const handle = (url, params) => {
            //ownKeys遍历对象所有属性名 Symbol类型,返回数组
            let keys = Reflect.ownKeys(params),
                str = ``,
                char = ''
            keys.forEach(key => {
                // encodeURIComponent只对问号参数编码(属性值)
                let val = encodeURIComponent(params[key])
                str += `&${key}=${val}`;
            });
            //截取字符串(截掉第一个&)
            str = str.substring(1);
            // 判断拼接问号
            char = url.indexOf('?') > -1 ? '&' : '?'
            return `${url}${char}${str}`

        };
        console.log(handle(url, obj));

12.给定一个数组,和一个数字n转化为子长度为n的二维数组

例如 arr=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 例如n=3输出结果[[1,2,3,[4,5,6],[7,8,9],[10]]

      let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        const change = function change(arr, n) {
            let newArr = [];
            for (let i = 0; i < arr.length; i += n) {
                console.log(i);//0 3 6 9
                newArr.push(arr.slice(i, i + n))
            }
            return newArr
        }
        console.log(change(arr, 3));

13.对象如何使用for of循环

    //每次方法执行返回一个迭代器对象
    Object.prototype[Symbol.iterator] = function () {
        //this-->obj
        let self = this,
            //拿到所有属性名(数组)
            keys = Reflect.ownKeys(self),
            //定义索引初始值
            index = 0;
        return {
            //每次for of执行调用next方法,done为true时结束循环
            next() {
                // 当索引大于数组长度时
                if (index >= keys.length) {
                    return {
                        value: undefined,
                        done: true
                    };
                }
                //索引小于数组长度时,每次索引++
                return {
                    value: self[keys[index++]],
                    done: false
                };
            }
        }
    }
    let obj = { name: 'lisa', age: 13, lx: 0 }
    for (let value of obj) {
        console.log(value);
    }

查找两个数组的重复项和不同项

不同项  content拼接 filter过滤  索引第一次出现的位置和最后一次出现的位置相同

相同项  双for循环两个数组做比较相同push到一个数组里边

let arr1 = [1, 2, 3, 7, 9]
let arr2 = [1, 2, 3, 8, 4]
//不重复项
function fn(a, b) {
    //filter 符合条件返回一个新数组
    return a.concat(b).filter((v, i, arr) => {
        //第一次出现的位置和最最后一次出现的位置相等就代表第一次出现
        return arr.indexOf(v) == arr.lastIndexOf(v)
    })
}
console.log(fn(arr1, arr2))
// 重复项
function fn2(a, b) {
    let newArr = []
    for (let i = 0; i < a.length; i++) {
        for (let j = 0; j < b.length; j++) {
            if (a[i] == b[j]) {
                newArr.push(a[i])
            }
        }

    }
    return newArr
}

console.log(fn2(arr1, arr2));

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值