这波 TikTok SDE NG 面试一共三轮,整体偏硬核。前两轮都是纯 coding,每轮两道算法题,时间卡得比较紧,考察重点在思路清晰度和代码完整性;题型以中高频算法为主,需要对复杂度和边界比较敏感。第三轮是 HM 面,从简历深挖项目经历,重点问 infra 背景与系统设计思路。下面逐题复盘。
一、第一轮 Coding
Q1:最多改一个元素,判断数组是否有序
题目:在允许最多修改数组一个元素的条件下,这个数组能否变成非递减有序?
从前往后遍历,找到第一个违反非递减的位置 i(即 nums[i] < nums[i-1])。此时有两种修复方式:把 nums[i-1] 调小到 nums[i],或把 nums[i] 调大到 nums[i-1]。选哪种取决于 nums[i-2]:
def check_possibility(nums) -> bool:
changed = False
for i in range(1, len(nums)):
if nums[i] < nums[i - 1]:
if changed: # 已经改过一次,第二次违反 -> 失败
return False
changed = True
# 优先把 nums[i-1] 压到 nums[i](不破坏更前面的序)
if i >= 2 and nums[i - 2] > nums[i]:
nums[i] = nums[i - 1] # 只能抬高 nums[i]
else:
nums[i - 1] = nums[i]
return True
时间 O(n)、空间 O(1)。关键是贪心选哪个改,不要无脑改后面那个。
Q2:树中到其他节点平均距离最小的节点
题目:找到树中「到其他所有节点平均距离最小」的节点,一条边算 1,要求 O(n)。
这是经典换根 DP(rerooting):先一次 DFS 求出根到所有节点的距离和 sum0 与每棵子树大小;再一次 DFS 换根,父节点答案推子节点:ans[child] = ans[parent] + (n - 2*size[child])。距离和最小的节点即答案。
def min_avg_distance(n, edges):
g = [[] for _ in range(n)]
for u, v in edges:
g[u].append(v); g[v].append(u)
size = [1] * n
ans = [0] * n
def dfs1(u, p, depth):
ans[0] += depth
for w in g[u]:
if w != p:
dfs1(w, u, depth + 1)
size[u] += size[w]
def dfs2(u, p):
for w in g[u]:
if w != p:
ans[w] = ans[u] + n - 2 * size[w]
dfs2(w, u)
dfs1(0, -1, 0)
dfs2(0, -1)
return ans.index(min(ans))
两次 DFS 共 O(n),避免对每个节点单独 BFS 的 O(n²)。
二、第二轮 Coding
面试官先 2 分钟闲聊(问最近项目里怎么优化数据库查询性能),然后直接进编码。
Q1:嵌套整数列表迭代器
题目:给定嵌套整数列表(元素是整数或嵌套列表),实现迭代器按顺序遍历所有整数,自己定义数据结构并实现 next() 和 hasNext()。
用栈逆序压入元素,hasNext() 时循环展开列表,直到栈顶是整数:
class NestedIterator:
def __init__(self, nestedList):
# 逆序压栈,栈顶始终是下一个待处理元素
self.stack = nestedList[::-1]
def next(self) -> int:
# hasNext() 保证栈顶是整数,直接弹出
return self.stack.pop()
def hasNext(self) -> bool:
while self.stack:
top = self.stack[-1]
if isinstance(top, int):
return True
# 栈顶是列表:弹出并逆序压回其内容
self.stack.extend(self.stack.pop()[::-1])
return False
面试官追问「为什么 next() 是摊还 O(1)」:每个元素最多入栈、出栈各一次,总操作量与元素数线性相关。记得覆盖「空嵌套列表」「多层嵌套」用例。
Q2:字母异位词分组(优于排序)
题目:将字母异位词分组,要求优于 O(nk log k)(k 为字符串最大长度)。
常规解法是排序字符串当 key(O(k log k)),但面试官要优化。用长度 26 的计数数组转 tuple 当 key,每个字符串处理是 O(k):
from collections import defaultdict
def group_anagrams(strs):
groups = defaultdict(list)
for s in strs:
count = [0] * 26 # "aab..." -> [2,1,0,...]
for ch in s:
count[ord(ch) - ord('a')] += 1
groups[tuple(count)].append(s) # tuple 可哈希,当 key
return list(groups.values())
面试官提示「能用质数乘积当 key 吗」,可以补充:质数乘积可能溢出,计数数组更安全,也更贴合生产场景。总复杂度 O(nk)。
三、第三轮 HM 面
全程围绕简历展开,更关注沟通和成长性。先自我介绍,再挑项目提问,重点问:
- 最有挑战性的项目(infra / 系统设计选型与落地)。
- 如何与队友协作。
- 遇到突发情况如何处理——可分享一段实习经历:因为什么导致失败、最后怎么解决并避免再犯,回答要能「圆回来」,技术细节也要到位。
这轮通常不考 coding,是「正常聊天」式,从你的表达决定是否合适。
四、总结
TikTok SDE NG 三轮:前两轮纯 coding 考思路清晰 + 代码完整 + 边界敏感(数组贪心、换根 DP、栈迭代器、计数 key),第三轮 HM 看沟通与成长。难点不在单题,而在快节奏下两题连做还要讲清复杂度。
FAQ
Q1:TikTok SDE NG 几轮?
三轮:前两轮纯 coding(每轮两题,时间紧),第三轮 HM 简历深挖 + infra/系统设计 + 行为题。
Q2:异位词分组为什么不用排序?
排序 key 是 O(k log k),面试官要求优于此。用长度 26 计数数组转 tuple 当 key,每串 O(k),总 O(nk),且避免质数乘积溢出风险。
Q3:嵌套迭代器怎么答得稳?
用栈逆序压入,hasNext() 循环展开列表直到栈顶是整数,next() 直接弹出。要能解释「每元素最多进出栈各一次」=> 摊还 O(1),并覆盖空列表与多层嵌套。
Q4:怎么应对两题连做的快节奏?
先 clarify 输入格式再落笔、边写边覆盖边界、主动讲复杂度。如需 TikTok 快节奏 coding 轮的限时陪练,或 VO代面 / VO辅助 的实时对接,可发岗位 JD 先做题型预测。
正在准备 TikTok 面试?
oavoservice 提供 TikTok SDE 全流程陪练:双题连做限时模拟、换根 DP/栈迭代器/计数 key 等高频题演练、HM 简历深挖与 infra 系统设计问答,也支持 VO代面 / VO辅助 的实时对接。教练含前大厂资深工程师,熟悉 TikTok「思路清晰 + 代码完整」的评分风格。
立即添加微信 Coding0201,获取 TikTok 真题与陪练。
联系方式
- 微信:Coding0201
- Email:[email protected]
- Telegram:@OAVOProxy