选择题
- 作用域,this指向
- IP地址、子网掩码
- 同步异步,执行顺序
- 网络攻击类型
- TCP相关
- 对称非对称加密
- 堆栈
- shell命令 (pwd rm cd之类的)
- 数组[-5…5,0…4,-1…10,-10…1]中多少个元素?
有7920个元素(上下界差值+1的乘积)
算法题
题目1
- 两个同学玩游戏,每次分数增加多的、减少少的、自己提高对方降低的,即差值大的人,可以嘲笑对方。现在允许改变某些关卡的分数,让两人可以不用嘲讽,求最少改变多少关?
输入如下
5
3 4 5 1 2
4 2 5 2 1
分析
差值都一样,则不用嘲讽
- 原来的分数
Tom 3 4 5 1 2
Jerry 4 2 5 2 1
二者分数差(-1最多,出现2次)
d_TJ -1 2 0 -1 1
分数间隔
d_T 1 1 -4 1
d_J -2 3 -3 -1
- 更改后分数
目的二者分数差
newd_TJ -1 -1 -1 -1 -1
新分数
newTom 3 1 4 1 0
newJerry 4 2 5 2 1
分数间隔
newd_T -2 3 -3 -1
newd_J -2 3 -3 -1
更改数 = 总数 - 两人分数差出现最多的数字的次数
代码
# 输入
N = 5
tom = [3,4,5,1,2]
jerry = [4,2,5,2,1]
# 差值
res = [tom[i] - jerry[i] for i in range(N)]
# 出现最多的次数
maxCount = res.count(max(res,key=res.count))
print(N - maxCount)
题目2
- 学生会有上下级关系,除了直属上下级,上级的上级也是上级,下级的下级也是下级。每个人有自己爱好,由小写字母表示。假设A的下级有B、C、D,他们的爱好分别是(A:c, B: d, C: d, D: e),则A管理下级的爱好数量为 2。求整个学生会所有人管理下级爱好的和。
输入(人数、爱好、有直属上下级关系的两个人)
5
abcdd
2 3
2 5
4 2
2 1
输出:
5
分析
- 首先构建无向、联通树
- 计算所有人管理爱好和
t h e S u m = h o b b i e s ( 1 ) + h o b b i e s ( 2 ) + h o b b i e s ( 3 ) + h o b b i e s ( 4 ) + h o b b i e s ( 5 ) = 3 + 2 + 0 + 0 + 0 = 5 theSum = hobbies(1) + hobbies(2) + hobbies(3) + hobbies(4) + hobbies(5) = 3+2+0+0+0 = 5 theSum=hobbies(1)+hobbies(2)+hobbies(3)+hobbies(4)+hobbies(5)=3+2+0+0+0=5
代码
def createTree(total,edges):
tree = [[] for _ in range(total)]
# print(tree) [[], [], [], [], []]
for left, right in edges:
tree[left-1].append(right-1)
tree[right-1].append(left-1)
# print(tree) [[1], [2, 4, 3, 0], [1], [1], [1]]
depth = [0 for _ in range(total)]
def dfs(current, father):
for child in tree[current]:
if child != father:
depth[child] = depth[current] + 1
dfs(child, current)
dfs(0, -1)
# print(depth) [0, 1, 2, 2, 2]
return depth
total = 5
edges = [[2,3],[2,5],[4,2],[2,1]]
depth = createTree(total,edges) # [0, 1, 2, 2, 2]
hobby_str = 'abcdd'
values = [{'depth':depth[i],'hobby':hobby_str[i]} for i in range(total)]
# values
#[{'depth': 0, 'hobby': 'a'},
# {'depth': 1, 'hobby': 'b'},
# {'depth': 2, 'hobby': 'c'},
# {'depth': 2, 'hobby': 'd'},
# {'depth': 2, 'hobby': 'd'}]
res = [[] for i in range(max(depth)+1)]
for line in values:
res[line['depth']].append(line['hobby'])
# res = [['a'], ['b'], ['c', 'd', 'd']]
ans = [0 for i in range(len(res))]
temp = []
for i in range(len(res)):
current = len(res) - i -1
temp += list(set(res[current]))
ans[current] = len(temp)
theSum = sum(ans[1:])
# temp
# ['d', 'c']
# ['d', 'c', 'b']
# ['d', 'c', 'b', 'a']
# ans = [4, 3, 2]
# theSum = 5
面试题
- 自我介绍-提问
- 项目介绍-提问
- 面试官介绍了项目组,反问
- MySQL 熟悉吗、如果已知一个查询语句异常(访问次数多),排查定位的方法
- Express 用到了什么
- js 基础型、引用型
- ES6 新特性
- 闭包、优缺点
- 内存泄漏
- 高阶函数、比如 array 的哪些方法是高阶函数
- 原型原型链
- apply call bind
- 模块依赖环的解决(盆友:死锁?)
- CSRF
- 性能调优的方法(也许也有想问负载均衡之类的?)
- Node的特点
- GC机制、哪些语言中有,C++呢
- 异步I/O
- 事件循环、方法
- require
- 笔试题4个(setTimeout、原型链、数组去重)
- 反问-结束
js 的事件循环是什么?
-
事件队列是一个存储着待执行任务的队列,其中的任务严格按照时间先后顺序执行,排在队头的任务将会率先执行,而排在队尾的任务会最后执行。事件队列每次仅执行一个任务,在该任务执行完毕之后,再执行下一个任务。执行栈则是一个类似于函数调用栈的运行容器,当执行栈为空时,JS 引擎便检查事件队列,如果不为空的话,事件队列便将第一个任务压入执行栈中运行。
-
因为 js 是单线程运行的,在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行。在执行同步代码的时候,如果遇到了异步事件,js 引擎并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当同步事件执行完毕后,再将异步事件对应的回调加入到与当前执行栈中不同的另一个任务队列中等待执行。任务队列可以分为宏任务对列和微任务对列,当当前执行栈中的事件执行完毕后,js 引擎首先会判断微任务对列中是否有任务可以执行,如果有就将微任务队首的事件压入栈中执行。当微任务对列中的任务都执行完成后再去判断宏任务对列中的任务。
-
微任务包括了 promise 的回调、node 中的 process.nextTick 、对 Dom 变化监听的 MutationObserver。
-
宏任务包括了 script 脚本的执行、setTimeout ,setInterval ,setImmediate 一类的定时事件,还有如 I/O 操作、UI 渲
染等。
什么是 CSRF 攻击?如何防范 CSRF 攻击?
-
CSRF 攻击指的是跨站请求伪造攻击,攻击者诱导用户进入一个第三方网站,然后该网站向被攻击网站发送跨站请求。如果用户在被
攻击网站中保存了登录状态,那么攻击者就可以利用这个登录状态,绕过后台的用户验证,冒充用户向服务器执行一些操作。 -
CSRF 攻击的本质是利用了 cookie 会在同源请求中携带发送给服务器的特点,以此来实现用户的冒充。
一般的 CSRF 攻击类型有三种:
-
第一种是 GET 类型的 CSRF 攻击,比如在网站中的一个 img 标签里构建一个请求,当用户打开这个网站的时候就会自动发起提
交。 -
第二种是 POST 类型的 CSRF 攻击,比如说构建一个表单,然后隐藏它,当用户进入页面时,自动提交这个表单。
-
第三种是链接类型的 CSRF 攻击,比如说在 a 标签的 href 属性里构建一个请求,然后诱导用户去点击。
CSRF 可以用下面几种方法来防护:
-
第一种是同源检测的方法,服务器根据 http 请求头中 origin 或者 referer 信息来判断请求是否为允许访问的站点,从而对请求进行过滤。当 origin 或者 referer 信息都不存在的时候,直接阻止。这种方式的缺点是有些情况下 referer 可以被伪造。还有就是我们这种方法同时把搜索引擎的链接也给屏蔽了,所以一般网站会允许搜索引擎的页面请求,但是相应的页面请求这种请求方式也可能被攻击者给利用。
-
第二种方法是使用 CSRF Token 来进行验证,服务器向用户返回一个随机数 Token ,当网站再次发起请求时,在请求参数中加入服务器端返回的 token ,然后服务器对这个 token 进行验证。这种方法解决了使用 cookie 单一验证方式时,可能会被冒用的问题,但是这种方法存在一个缺点就是,我们需要给网站中的所有请求都添加上这个 token,操作比较繁琐。还有一个问题是一般不会只有一台网站服务器,如果我们的请求经过负载平衡转移到了其他的服务器,但是这个服务器的 session 中没有保留这个 token 的话,就没有办法验证了。这种情况我们可以通过改变 token 的构建方式来解决。
-
第三种方式使用双重 Cookie 验证的办法,服务器在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串,然后当用户再次向服务器发送请求的时候,从 cookie 中取出这个字符串,添加到 URL 参数中,然后服务器通过对 cookie 中的数据和参数中的数据进行比较,来进行验证。使用这种方式是利用了攻击者只能利用 cookie,但是不能访问获取 cookie 的特点。并且这种方法比 CSRF Token 的方法更加方便,并且不涉及到分布式访问的问题。这种方法的缺点是如果网站存在 XSS 漏洞的,那么这种方式会失效。同时这种方式不能做到子域名的隔离。
-
第四种方式是使用在设置 cookie 属性的时候设置 Samesite ,限制 cookie 不能作为被第三方使用,从而可以避免被攻击者利用。Samesite 一共有两种模式,一种是严格模式,在严格模式下 cookie 在任何情况下都不可能作为第三方 Cookie 使用,在宽松模式下,cookie 可以被请求是 GET 请求,且会发生页面跳转的请求所使用。
相关文章