Table of contents
Open Table of contents
💬 一、基础知识类问题
1. 工作中常用的数据结构有哪些?为什么好用?
dict
:哈希表结构,查询和插入效率高(O(1)),最常用于快速查找、频次统计list
:顺序结构,灵活适配栈/队列等,使用频繁set
:用于去重与集合操作,查找效率高(O(1))deque
:双端队列,适合实现滑动窗口heapq
:优先队列场景,如找 Top K
总结: 后端开发中,选用合适的数据结构能极大提高系统性能和代码简洁性。
2. 哈希表怎么实现?哈希冲突怎么解决?
- 哈希表使用哈希函数将 key 映射为数组索引
- 冲突处理:
- 链式法:每个桶挂链表
- 开放寻址法:如线性探测、二次探测
- 插入、查询平均时间复杂度 O(1)
面试官补充问:
- Q:key 有序怎么办?
- A:可使用
SortedDict
或哈希表 + 有序辅助结构
- A:可使用
3. 跳表是什么?
- 跳表是一种支持快速查找的数据结构,用多层有序链表实现平均 O(log n) 查找
- 实现比红黑树简单,支持范围查询、顺序遍历等
- Redis 的 zset 就用跳表实现
4. 如何判断海量数据中 key 是否存在?
使用布隆过滤器(Bloom Filter)
- Bit 数组 + 多个哈希函数
- 插入 key:多个 bit 位置置为 1
- 查询 key:若任一位置为 0 → 一定不存在;全为 1 → 可能存在
- 空间占用小,误判可控,常用于黑名单检测、缓存穿透防护
5. 后端与前端在职责和要求层面上的区别?
- 前端:负责 UI 展示、用户交互,关注体验、响应性
- 后端:负责数据处理、业务逻辑、系统稳定性
- 后端要求更高的数据结构能力、系统设计能力、并发控制、容错机制
6. 为什么说后端稳定是第一位?
后端系统支撑了整个业务逻辑和数据流转,一旦出错,后果严重如下单失败、支付出错,因此稳定性(如幂等、限流、熔断、超时控制、数据一致性)始终是后端开发的首要目标。
7. 常见的消息队列有哪些?
消息队列 | 特点和场景 |
---|---|
Kafka | 高吞吐、分区顺序、大数据处理 |
RabbitMQ | AMQP 协议、灵活路由、可靠性高 |
RocketMQ | 支持事务、延迟消息、分布式一致性 |
Redis Stream | 轻量级、低延迟、已使用 Redis 场景 |
8. 常见的分布式框架有哪些?
方向 | 框架 |
---|---|
微服务 | Spring Cloud, Dubbo, gRPC |
数据存储 | HDFS, Ceph, TiDB, HBase |
协调注册 | Zookeeper, Etcd, Nacos |
任务调度 | ElasticJob, XXL-Job |
中间件 | Kafka, Redis, RocketMQ |
容器编排 | Kubernetes |
9. MySQL 分布式场景下,如何保证可用性与一致性?
- 单库:靠事务(ACID)保证强一致
- 主从复制:提升可用性,但读写可能不一致(需使用半同步 + 主库读)
- 分库分表:
- 强一致方案:XA 两阶段提交(慢)
- 实际常用:本地事务 + 可靠消息 + 异步补偿(最终一致)
- 可用性保障手段:读写分离、主从切换、服务熔断、健康检查等
10. Socket 编程介绍 / 阻塞与非阻塞的区别
- Socket:网络编程的核心 API,支持 TCP/UDP 通信
- 阻塞:
recv()
会卡住线程直到有数据 - 非阻塞:立即返回结果,结合
select
/epoll
实现高并发服务
11. 网络协议 QUIC 是什么?
- Google 推出基于 UDP 的现代传输协议
- 整合 TCP + TLS + HTTP/2 优点
- 支持 0-RTT 握手、多路复用、内置加密
- 已广泛应用于 HTTP/3
💻 二、算法题汇总
✅ 题目 1:合并两个有序数组
题目: 给定两个有序数组,返回合并后的有序数组。
思路:
- 使用双指针遍历两个数组
- 比较当前元素,取小的放入结果
- 最后拼接未处理完的那一方
代码:
def merge_sorted_arrays(a, b):
i = j = 0
res = []
while i < len(a) and j < len(b):
res.append(a[i] if a[i] < b[j] else b[j])
i += a[i] < b[j]
j += a[i] >= b[j]
return res + a[i:] + b[j:]
面试官追问:
- 如果将
and
改成or
会怎样?- 答:可能访问越界,因为一个数组结束后另一个可能还未结束。
✅ 题目 2:用只返回 0/1 的函数 f()
生成等概率的 0~7
思路:
- 0~7 = 3 个二进制位表示范围
- 用
f()
调用三次,拼出一个 3 位数,刚好覆盖 0~7 的 8 种可能
代码:
def f():
return random.randint(0, 1)
def rand_0_7():
return (f() << 2) | (f() << 1) | f()