上来就三道算法、23年腾娱互动、Golang后端面试复盘(已挂)、经验可借鉴
一、面试流程(2小时)
1、45分钟笔试(三道算法)
大数相乘: 没有思路
有序链表合并: 有思路,没有写出来
LRU之前看过: 有思路,没有写出来
2、负责项目介绍(难点/挑战点/技术选型/为什么这么选择)
重点: 介绍是一门艺术活,说的好非常不一样,今天感觉就吃在表达上面了,大家记得提前准备好这些
我讲述的是一个后台SQL慢查询的列子,慢的主要原因是关联表太多,临时解决方案是分段查询,终极解决方案是宽表
中间还插入了技术选型:
1、宽表为什么用DB不用ES?(个人复盘观点哈。 主要是在数据量方面差异,ES能支持更多数据搜索)
2、索引优化(覆盖索引/联合索引/最左原则这些什么也可讲讲)
3、如何分段查询(分多步查询,单表查询效率快)
4、自己设计的有用过其他数据库么?(想不到了 真的只有Mysql/Redis/Es)
3、Mysql、网络深挖
1、事物特性?(A 原子性、C 一致性、I 隔离型、D 持久型)
2、隔离型实现原理?(MVCC)
3、MVCC实现原理?(版本链路 + 事物ID + 活跃事物ID)
事物开启、申请 trac_id
记录当时活跃事物ID、低的叫低水位、高的 + 1 叫做高水位
trac_id < 低水位 过去事物创建,可以读
trac_id > 低水位 过去事物创建,不可以读
中间的分两种情况、在活跃事物id中,不可以读,其余可读
4、隔离级别、解决问题?
读已提交(解决脏读)
读未提交
可重复读(解决脏读、不可重复读)
序列化(解决脏读、幻读、不可重复读)
5、事物如何保证一致性、持久性?(未答上)
一致性:原子性-undolog + 一致性redolog + 隔离级别MVCC 共同保障
持久性:redolog,innodb引擎特有、WAL循环写入,先写redolog buffer,在写入磁盘,具体策略不同
6、两阶段提交流程?(未答上)
说了mysql 的两阶段提交, 保证 redolog 和 binlog 统一
7、 平时如何解决问题,有什么收获?
遇到问题,自己先想解决方案、在查询业界的整体处理方案、整合好自己的最佳方案,和部门高职级商谈,定下最终方案,告知产品相关影响点,及时通知业务方整顿,避免异常情况产品
收获:收获了一份解决类型问题通用答案、为后续加入团队人员留下参考文档,增加团队影响力
8、TCP 为什么沾包?
减少多个包来换传输的网络开销
9、UDP 有没有沾包?
TCP是字节流传输
UDP面向报文传输,UDP没有沾包
10、一般如何解决沾包?HTTP是如何解决?
解决沾包:
包固定长度
添加特殊字符串隔离
包头 + 包体格式
HTTP 是通过 (协议头包头 + 包体格式解决)
4、反问环节
1、介绍一下业务?
小世界运营业务、用户相关
2、目前框架
语言:Go
框架:微服务
中间件:Kafaka、Redis、MongDB
搜索:ES
3、麻烦让面试总结一下?如何学习补充?
加强算法训练、落实代码落地
项目没有亮点?描述不好?项目简单?从业务思考?自己设计模块简单?
基础知识还需要加强
二、再来一遍
三道算法(真题)
# 大数相乘
func multiply(num1 string, num2 string) string {
if num1 == "0" || num2 == "0" {
return "0"
}
len1, len2 := len(num1), len(num2)
strArr := make([]int, len1+len2)
for i := len1 - 1; i >= 0; i-- {
n1 := int(num1[i]) - '0'
for j := len2 - 1; j >= 0; j-- {
n2 := int(num2[j]) - '0'
// 乘基和位置有关系
tmpNum := n1 * n2
strArr[i+j+1] += n1 * n2
}
}
// 处理乘基数据
for ii := len1 + len2 - 1; ii > 0; ii-- {
strArr[ii-1] += strArr[ii] / 10
strArr[ii] = strArr[ii] % 10
}
// m1Str * m2Str 最大位数: m + n, 最小位数: m + n -1
idx := 0
if strArr[0] == 0 {
idx = 1
}
// 拼接字符串
str := ""
for i := idx; i < len1+len2; i++ {
str += strconv.Itoa(strArr[i])
}
return str
}
# 合并有序链表
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
if list1 == nil {
return list2
}
if list2 == nil {
return list1
}
head := &ListNode{Val:-1}
cur := head
for list1 != nil && list2 != nil {
if list1.Val < list2.Val {
cur.Next, list1 = list1, list1.Next
} else {
cur.Next, list2 = list2, list2.Next
}
cur = cur.Next
}
if list1 != nil {
cur.Next, list1 = list1,list1.Next
} else {
cur.Next, list2 = list2, list2.Next
}
return head.Next
}
# LRU [双向链表]
type DLinkList struct {
Key, Val int
Prev, Next *DLinkList
}
type LRUCache struct {
Cap, Len int
CacheMap map[int]*DLinkList
Head, Tail *DLinkList
}
func Constructor(capacity int) LRUCache {
// 初始化
head, tail := InitDLinkList(0, 0), InitDLinkList(0, 0)
head.Next, tail.Prev = tail, head
lru := LRUCache{
Cap: capacity,
Len: 0,
CacheMap: map[int]*DLinkList{},
Head: head,
Tail: tail,
}
return lru
}
func (this *LRUCache) Get(key int) int {
if _, ok := this.CacheMap[key]; !ok {
return -1
}
// 返回值,并移动到最前面
node := this.CacheMap[key]
this.MoveToHead(node)
return node.Val
}
func (this *LRUCache) Put(key int, value int) {
if _, ok := this.CacheMap[key]; !ok {
newNode := InitDLinkList(key, value)
this.CacheMap[key] = newNode
this.AddToHead(newNode)
this.Len++
// 移除最后一个元素
if this.Cap < this.Len {
tailKey := this.RemoveTail()
this.Len--
delete(this.CacheMap, tailKey)
}
} else {
node := this.CacheMap[key]
node.Val = value
this.MoveToHead(node)
}
}
func InitDLinkList(key, val int) *DLinkList {
dl := &DLinkList{
Key: key,
Val: val,
}
return dl
}
func (this *LRUCache) MoveToHead(dl *DLinkList) {
this.removeNode(dl)
this.AddToHead(dl)
}
func (this *LRUCache) removeNode(dl *DLinkList) {
// 移除 node 节点
dl.Prev.Next = dl.Next
dl.Next.Prev = dl.Prev
}
func (this *LRUCache) AddToHead(dl *DLinkList) {
// node 节点
dl.Next = this.Head.Next
dl.Prev = this.Head
// node 后面节点
this.Head.Next.Prev = dl
// head 节点
this.Head.Next = dl
}
func (this *LRUCache) RemoveTail() int {
tailNode := this.Tail.Prev
this.removeNode(tailNode)
return tailNode.Key
}
三、自我感受
1、算法真的逃避不了,面试在哪里都需要刷
2、什么难就问什么,多了解了解原理性东西
3、总结项目亮点、需要凝练、另外需要增强表述与表达
三、复盘
1、一定要下个录屏软件,把和面试官面试过程录下来,进行反复观看和复盘
2、加强弱点补充,我的在于深入原理和算法
3、寻找项目亮点、增加语言表述能力,从业务思考优化难点