字节跳动面试小结

Uncategorized
3.8k words

面试小结

这一次面试没有想象中的那么压力山大,面试官也没有去死咬着某个知识点去提问,而是通过投递的简历来提问,其中计算机操作系统相关的题目较多,而我有对计算机系统方面的线程进程问题又比较了解,在这个部分表现得还算过得去,但是在于存储的方面我确实没有一个很好的实践积累,回答的大多都是在理论上的知识点,还有设备IO方面,我知道的也不是很多,面试官看我不是很清楚也就没有深挖。计算机网络相关的基础没有问到,不知道是不是看我的简历上有一两个网络编程的经验就跳过了。

缺少知识点:多线程相关的细节,Mysql,Redis,哈希表,红黑树

面试除了基础知识的提问,还考察了在设计项目上的思路,例如操作系统上如何去降低一个响应的时间:我除了进程之外也懂得不多,我就回答的是可以优化进程调度的一个策略,例如调整时间片大小,在线程之下创建亚线程。内存我直接不管了,另外加多CPU支持并行,多的我面试的时候也没有想到。

以下是AI生成的其他回答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 I/O优化
异步I/O:用非阻塞I/O(如epoll、io_uring)替代同步阻塞调用。

缓冲和批处理:合并小I/O请求为大操作(如磁盘写合并)。

SSD/高速存储:替换机械硬盘,降低I/O延迟。

内核参数调优
调整调度器:如Linux的CFS(完全公平调度器)参数或改用实时调度策略(SCHED_FIFO)。

中断优化:启用中断负载均衡(irqbalance),或绑定中断到特定CPU。

亚线程/协程:将任务拆分为更轻量级的单元(如协程、用户态线程),减少阻塞。

CPU绑定(Affinity):将关键进程绑定到特定CPU核心,避免缓存失效和迁移开销。

网络相关场景题

还有在网络繁忙的时候该如何解决大量访问的问题,这里我回答的是一个限流,以下是常见的限流算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
令牌桶(Token Bucket):

固定速率生成令牌,请求需消耗令牌(突发流量允许一定峰值)。

实现工具:Nginx limit_req、Redis + Lua脚本。

漏桶(Leaky Bucket):

请求以恒定速率处理(平滑流量,严格限制突发)。

固定窗口/滑动窗口计数:

统计单位时间内的请求数(如每分钟100次),滑动窗口更精确但开销略高。

自适应限流:

根据系统负载动态调整阈值(如CPU、队列长度),如Netflix的Hystrix。

以下是AI回答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
流量整形与负载均衡
队列缓冲:用消息队列(Kafka、RabbitMQ)异步处理请求,削峰填谷。

负载均衡:

横向扩展:增加服务实例,通过LB(如Nginx、HAProxy)分发流量。

智能路由:根据服务器负载动态分配请求(如Least Connections算法)。

服务降级与熔断
降级:关闭非核心功能(如推荐服务),返回缓存或默认值。

熔断:当错误率超过阈值时,短暂拒绝请求(如Hystrix、Resilience4j)。

服务隔离:将关键服务与非关键服务分离(如线程池隔离)。

缓存优化
多级缓存:

客户端缓存 → CDN → 服务端缓存(Redis)→ 数据库缓存。

热点数据预加载:提前缓存高频访问数据(如秒杀商品库存)。

弹性伸缩与云原生方案
自动扩缩容:Kubernetes HPA、AWS Auto Scaling。

Serverless:突发流量由无服务函数(如AWS Lambda)处理。

协议与连接优化
长连接复用:减少TCP握手开销(如HTTP/2、gRPC)。

压缩数据:减小传输体积(如Gzip、Protobuf)。

快速失败:设置超时时间(如TCP SYN队列调优)。

哈希表和红黑树

问题“哈希表和红黑树有什么区别?如何选择?”
回答模板

  1. 先对比核心特性
    “哈希表基于哈希函数,理想情况下查询是O(1),但可能因冲突退化;红黑树是自平衡二叉搜索树,稳定在O(log n),且支持有序遍历。”
  2. 提优缺点
    “哈希表内存占用大但查询快,适合字典类场景;红黑树更省内存且有序,适合范围查询。”
  3. 举例应用
    “比如Java的HashMap用哈希表实现快速查找,而TreeMap用红黑树保证键的有序性。”
  • 哈希表如何解决冲突?
    → 拉链法(链表+红黑树,如Java 8的HashMap)、开放寻址法。
  • 红黑树 vs AVL树?
    → 红黑树牺牲严格平衡性换取更少的旋转操作,适合频繁插入删除的场景。

算法题目

有思路的,可惜没有写出来,以下是题目样例,具体的输入我想不起来了

我理解的这是一种压缩的方式:

例如字符串 ab[avv]{2}dd 代表的是 abavvavvdd,要求写一个算法输入字符串,输出对应的字符串,这一道题我的理解是将 [ 放入栈结构里面,记录右侧下表,遇到]时候弹栈,读取后面的循环次数(限制为2-9,不然更麻烦了),循环输出,但是这里有个重点是这样一个[ ] 是要求可以嵌套使用的,最后写出来的只能处理不嵌套的一种样式,以下是 AI生成的算法,学学看吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.algorithm;
import java.util.Stack;

public class Interview {
public static void main(String[] args) {
String s1 = "ab[avv]{2}dd";
System.out.println(decodeString(s1)); // 输出: abavvavvdd

String s2 = "a[b[c]{2}]{3}d";
System.out.println(decodeString(s2)); // 输出: abccbccbccd
}

// 手动实现的字符串重复方法(兼容 Java 8)
public static String repeat(String str, int times) {
if (times <= 0) {
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < times; i++) {
sb.append(str);
}
return sb.toString();
}

public static String decodeString(String s) {
Stack<StringBuilder> strStack = new Stack<>();
Stack<Integer> numStack = new Stack<>();
StringBuilder currentStr = new StringBuilder();
int i = 0;
int n = s.length();

while (i < n) {
char c = s.charAt(i);
if (c == '[') {
// 遇到 '[', 压栈当前状态
strStack.push(currentStr);
currentStr = new StringBuilder();
i++;
} else if (c == ']') {
// 遇到 ']', 准备读取 '{n}'
i++; // 跳过 ']'
if (i < n && s.charAt(i) == '{') {
i++; // 跳过 '{'
if (i < n && Character.isDigit(s.charAt(i))) {
int repeatTimes = s.charAt(i) - '0';
i++; // 跳过数字
if (i < n && s.charAt(i) == '}') {
i++; // 跳过 '}'
}
// 弹出栈顶状态并使用自定义的repeat方法
StringBuilder prevStr = strStack.pop();
String repeatedStr = repeat(currentStr.toString(), repeatTimes); // 使用自定义repeat
prevStr.append(repeatedStr);
currentStr = prevStr;
}
}
} else {
// 普通字符,直接追加
currentStr.append(c);
i++;
}
}

return currentStr.toString();
}
}

其实看起来还是有点困难的,主要还是我Java还没有学习到字符串相关的常用类String那里,哎,慢慢学吧

Comments