2022快手前端校招一面

第一题:一个乱序的0-n数组,求确失的那个数.O(n),空间复杂度o(1)
[0,1] 缺失2
[0,3,1,4] 缺失2
1、数组完整元素为0-n,缺少一个元素后,下标为0-n-1。所以可以将数组内元素相加与0-n相加的结果比较,得出缺失的元素

function losNumber(arr){
    let sum = 0,curSum=0;
    for(let i =0 ;i<arr.length;i++){
        sum+=i;
        curSum+=arr[i]
    }
    return sum+arr.length-curSum
}

2、异或。一个数异或自身为0,0异或任何数为其自身,aXORbXORa=b;所以可以把数组中的元素异或一遍,同时把0-n异或一遍,再将2者异或。相当于一串数字异或,只有一个数字出现了一次,其他数字出现偶数次0

function losNumberXOR(arr){
    let sum = 0,curSum=0;
    for(let i =0 ;i<arr.length;i++){
        sum=sum^i;
        curSum=curSum^arr[i]
    }
    return sum^arr.length^curSum
}

第二题:一颗二叉树,求每一层值的节点的平均值
就是层序遍历树,求每层的平均值。可以使用BFS。首先记录一层的值,若当前节点有子节点,将子节点存入临时队列,等当前队列比遍历完后,开始遍历子队列。

function printLevel(root) {
    if (!root) return [];
    let result = [], temp = [], curQueue = [root], resLevel = [],sum = 0;
    let p;
    while (curQueue.length > 0 || temp.length > 0) {
        if (curQueue.length === 0) {  // 当队列长度为0,说明当前层级所有节点已经访问过
            result.push(sum/resLevel.length);    //保存当前层级的值
            curQueue = temp;    //访问下一层
            temp = [];
            resLevel = [];
        }
        p = curQueue.shift();
        if (p) {
        sum+=p.val;
            resLevel.push(p.val);
            temp.push(p.left);
            temp.push(p.right);
        }
    }
    return result;
}

function myPrintLevel(root) {
    if (!root) return [];
    let result = [], temp = [], curQueue = [root], resLevel = [];
    while (curQueue.length > 0 || temp.length > 0) {
        for (let p of curQueue) {
            if (p) {
                resLevel.push(p.val);
                temp.push(p.left, p.right)
            }
        }
        if (resLevel.length > 0) {
            result.push(resLevel);
        }
        curQueue = temp;
        temp = [];
        resLevel = [];
    }
    return result;
}

第三题:一个2维数组,从第一层到租后一层,求最小权值路径
动态规划。当前坐标的下一步应该走的一定是可选路径中最短的,即从可选路径中选择下一坐标到终点最短的节点接上。
所以可以由最下层到最上层,记录当前坐标到最下层的最短路径。
状态转义方程: memo[x][y]=matrix[x][y]+Math.min(dp(x+1,y-1), dp(x+1,y), dp(x+1,y+1));
为了减少递归,用memo记录已经走过的地方。

let minFallingPathSum = function(matrix) {
    //记录已经走过的路径
    let memo = matrix.map((m)=>{
        return m.map(n=>101)
    });
    function dp(x,y){
        if(x<0||y<0||x>=matrix[0].length||y>=matrix[0].length){
            return Infinity;
        }
        if(memo[x][y]!=101){
            return memo[x][y];
        }
        else if(x==matrix[0].length-1){
            memo[x][y]= matrix[x][y];
            return memo[x][y]
        }
        memo[x][y]=matrix[x][y]+Math.min(dp(x+1,y-1), dp(x+1,y), dp(x+1,y+1));
        return memo[x][y];
    }
    let min=99999;
    for(let i=0;i<matrix[0].length;i++){
        min = Math.min(min,dp(0,i));
    }
    console.log(memo);
    return min;
};

第三题:网络知识

CDN

简介:

https://juejin.cn/post/6913704568325046279

CDN简单来说就是为了加快请求的首次响应速度,在源服务器和用户间实现的一种网络架构。具体实现有缓存代理服务器。

307状态码:

307,302,303都是临时重定向。
302会导致重定向后发往原url的post请求变成get请求。
307则不会。
303效果同302,也会改变请求方式,但是重定向导向的资源一般对原请求资源的描述。

区别

在这里总结一下,从实际效果看:302 允许各种各样的重定向,一般情况下都会实现为到 GET 的重定向,但是不能确保 POST
会重定向为 POST;而 303 只允许任意请求到 GET 的重定向;307 和 302 一样,除了不允许 POST 到 GET 的重定向。

简要历史原因

那为什么有了 307 和 303 还需要 302呢?把总结放在最前面。302 在最初的定义中,内容和现在的 307
是一样的,不允许重定向方法的改写(从 POST 到 GET,由于 GET 不应该有 body,实际上 body
也被改了)。但是早期浏览器在实现的时候有的实现成 303 的效果,有的实现成 307 的效果。于是在之后的标准,302
在某些浏览器中错误的实现被写进规范,成为 303,而 302 原本的效果被复制了到了 307。在最近的一次标准修订中,302
标准被修改成不再强制需要维持原请求的方法。所以就产生了现在的 302、303 和 307

第四题:vue2.0中的composition组合式api

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晨灰ash2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值