微软 26 Intern 面经|微软实习面试|Microsoft Internship 真题
Microsoft 2026 Intern 两轮面试复盘:BQ 偏合作与 Ownership;Coding 以口述需求、边聊边加约束为主,第一轮文件路径管理器(树 + HashMap),第二轮消息订阅系统(双向映射),附参考实现。
面试整体结构
一共两轮,每轮 45 分钟,中间休息 15 分钟。我的两轮结构挺相似:
| 时间 | 内容 |
|---|---|
| 前 15 分钟 | BQ |
| 中间约 20 分钟 | 做题 |
| 最后 5 分钟 | 我提问 |
不过和朋友交流之后发现,微软的面试流程没那么模板化,不同面试官风格差异挺大:有的会弱化甚至直接跳过 BQ,有的在做题过程中不断追问 follow-up,把时间拉得很长。
BQ:偏合作与 Ownership,不会技术深挖
BQ 整体压力不大,明显不像 Amazon 那样反复深挖,但还是建议提前准备好几个完整的故事。问题更多集中在合作、冲突处理、Ownership,不太会往技术细节上 deep dive。
Coding 总体风格:口述需求 + 讨论驱动
两道题都比较开放。两位面试官都没有把完整题目直接贴到 HackerRank 里,而是口头描述需求,边聊边补充约束和功能,更像一个小型的 design + 实现的讨论。
第一轮:文件路径管理器(基于接口约束的数据结构设计)
题目
实现一个简单的文件路径管理器,核心需求:
addPath(path):创建路径,保证路径层级合法,并且不能重复创建已存在的路径getParent(path):返回某个路径的父路径
题目本身不复杂,但面试官更关心你怎么建模路径结构,以及在保证效率的前提下如何处理非法输入和边界情况。
思路
围绕一棵树展开:每个节点用 HashMap 维护子节点映射,从 root 开始逐层解析 path。
面试过程中面试官不断确认细节:
- 中间路径不存在时,要不要允许创建?
- 重复 add 时应该返回什么?
- 整体时间复杂度是不是和路径深度成正比?
整体感觉不像是在考你会不会这道题,而是看你能不能把约束想清楚、把设计讲清楚。
参考实现
这里按「父路径必须已存在、重复创建返回 False」的约定实现,面试时要先和面试官确认这些规则:
class PathManager:
def __init__(self):
self.root = {} # 每个节点:{子目录名: 子节点}
@staticmethod
def _split(path):
"""'/a/b' -> ['a', 'b'];不合法返回 None"""
if not path or not path.startswith("/") or path == "/":
return None
parts = path[1:].split("/")
return parts if all(parts) else None # 拒绝 '//'、结尾的 '/'
def add_path(self, path):
parts = self._split(path)
if parts is None:
return False
node = self.root
for name in parts[:-1]: # 中间路径必须已存在
if name not in node:
return False
node = node[name]
if parts[-1] in node: # 已存在,不重复创建
return False
node[parts[-1]] = {}
return True
def exists(self, path):
parts = self._split(path)
node = self.root
for name in parts or []:
if name not in node:
return False
node = node[name]
return parts is not None
def get_parent(self, path):
"""返回父路径;顶层路径的父路径是 '/';路径不存在返回 None"""
if not self.exists(path):
return None
parent = path.rsplit("/", 1)[0]
return parent or "/"
复杂度:add_path 和 get_parent 都是 O(d),d 是路径深度。
代码写完后,面试官没有让我实际跑测试,只是快速过了一下 corner case 和复杂度,就直接进入了 QA。
第二轮:消息订阅系统(状态变化 + 查询)
题目
场景是一个消息订阅系统,需要实现:
subscribe(user, topic)unsubscribe(user, topic)query(topic):返回当前订阅了某个 topic 的所有用户
需求看起来很简单,但面试官过程中不断加条件:
- 用户可能重复订阅
- 取消一个不存在的订阅该如何处理
- 如何保证
query的效率
思路
核心是双向映射:topic → 用户集合 保证 query 高效,user → topic 集合 支持按用户反查。这一轮明显更强调你对数据一致性和状态变化的理解:两个映射必须同时更新,不能出现一边有、一边没有的情况。
面试官还会顺着实现追问:
- 如果未来要支持按用户反查订阅列表怎么办?
- 数据量变大时,内存和性能怎么权衡?
整体更像一个逐步演进的小系统设计。
参考实现
from collections import defaultdict
class PubSub:
def __init__(self):
self.subscribers = defaultdict(set) # topic -> users
self.topics = defaultdict(set) # user -> topics(按用户反查)
def subscribe(self, user, topic):
"""重复订阅返回 False,状态不变"""
if user in self.subscribers[topic]:
return False
self.subscribers[topic].add(user)
self.topics[user].add(topic)
return True
def unsubscribe(self, user, topic):
"""取消不存在的订阅返回 False,不报错"""
if user not in self.subscribers.get(topic, ()):
return False
self.subscribers[topic].discard(user)
self.topics[user].discard(topic)
if not self.subscribers[topic]: # 清理空集合,避免内存一直增长
del self.subscribers[topic]
if not self.topics[user]:
del self.topics[user]
return True
def query(self, topic):
return set(self.subscribers.get(topic, ()))
def topics_of(self, user):
return set(self.topics.get(user, ()))
Follow-up 参考思路:两个映射都是 O(1) 增删,
query是 O(订阅者数量)。数据量很大时,热门 topic 的订阅者可能有百万级,可以对query结果分页返回;内存不够时把映射放进外部存储(比如 Redis 的 Set),按 topic 分片;如果只关心订阅人数,单独维护计数,不必返回整个集合。
这一轮 QA 聊得特别久,从团队协作、过往项目一直聊到对不同业务场景的偏好,最后还超时了大约 5 分钟才结束。
总体感受
- 这次是大组统一招人,HC 比较充足,具体分到哪个 team 目前还不确定。
- 微软的 Coding 更像「口述需求 + 讨论驱动的小设计」:先问清约束、讲清建模,再写代码,比一上来就写更重要。
- BQ 不深挖技术细节,但合作、冲突、Ownership 这几类故事要提前准备好。
看完有收获? 欢迎交流。
交流面经、互相 mock、内推信息,都可以找我。
