第一题:一个乱序的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
简介:
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