公司动态
网易2023校招文本挖掘算法工程师笔试复盘与备战指南
先交代一下背景我为网易2023校招笔试的“文本挖掘算法工程师提前批”做过完整复盘也带过几个学弟学妹备战同类岗位。这个岗位名字看着很垂直但笔试内容并不只有文本挖掘。真正参加过的人会明白这类考试的门道不在题有多难而在于你知不知道它考什么、用什么样的优先级去准备。这篇就是把我实际踩过的坑、刷过的题、总结出的套路一次性写出来给正在准备校招算法岗的人一份能直接照做的参考。1. 网易2023校招笔试复盘文本挖掘算法工程师到底考什么1.1 先搞清楚岗位定位再谈刷题很多人拿到“文本挖掘算法工程师”这个岗位名第一反应是把精力全扑在分词、TF-IDF、Word2Vec这些文本专属知识点上。方向没错但不够完整。从岗位的实际工作内容反推笔试要求文本挖掘工程师要处理的是非结构化文本数据的抽取、清洗、建模、检索和挖掘这意味着笔试一定覆盖三块文本处理基础、机器学习/深度学习算法、通用编程能力。提前批的笔试和正式批有个明显区别提前批更看重候选人的“算法功底”和“理解深度”因为后面还有多轮面试等着你笔试更像是一个快速筛选器。所以笔试题目往往不会出特别偏门的内容反而喜欢在经典算法上做文章比如KMP、BM25、排序、动态规划这些看起来基础但能在短时间内把一个人的水平拉开。我在准备时先做了一件事把网易往年的笔试题型分布梳理了一遍。虽然没有官方真题流出但结合公开的面经和常见的校招笔试模式可以总结出下面这个对应关系。这个分布不保证每年完全一样但方向基本稳定照着准备不会吃亏题型大致占比考察重点典型内容选择题30%-40%基础概念与计算KMP的next数组、排序复杂度、机器学习公式、概率统计编程题30%-40%代码实现与算法设计字符串处理、文本相似度、动态规划、贪心简答题/问答题20%-30%系统设计与方案选型分词系统设计、文本分类方案、检索排序思路1.2 提前批笔试的题型分布和应对策略从我的实际应试经验来看选择题是最容易拿分也最容易丢分的部分。说不容易是因为它覆盖面很广数据结构、算法、机器学习、深度学习、概率统计都可能出现说容易是因为它考的是单点知识不需要你现场推演复杂的推导。应对选择题的核心策略就是“背熟概念加动手算一遍”尤其是KMP的next数组、各种排序算法的时间复杂度、TF-IDF的计算、朴素贝叶斯的概率估计这些都是高频考点。编程题则是整个笔试的重头戏。网易的编程题一般在线评测环境是常见的牛客网或赛码网支持多种语言。我的建议是不要贪心选你最有把握的一门语言就行C和Python都是稳妥选择。文本挖掘方向的编程题经常会用字符串和文本相似度来出题比如计算两个字符串的编辑距离、实现一个简单的分词函数、用余弦相似度计算两个句子的相似度这些题目代码量不大但非常考验边界处理能力。简答题反而是很多人忽视的部分。它考的是一种“把问题想明白、用文字说清楚”的能力比如让你设计一个在线评论的情感分析系统或者解释为什么BM25比TF-IDF更适合搜索引擎。这类题没有标准答案阅卷人看的是你的思维框架、对技术的理解深度和表达能力。2. 文本挖掘专项考点从分词到BM25的核心公式拆解2.1 中文分词与关键词提取最大匹配算法怎么考中文分词是文本挖掘的第一道工序也是笔试中经常出现的题目。英文文本按空格切分就行中文不行“武汉市长江大桥”到底切分成“武汉市/长江大桥”还是“武汉/市长/江大桥”需要算法来解决。笔试考分词不会让你实现一个完整的分词器但高频出现的是“正向最大匹配”和“反向最大匹配”的实现题以及它们之间差异的原理题。正向最大匹配的思路很直白从左往右扫描每次都尝试匹配最长的词。假设词典中有“武汉”“武汉市”“长江”“长江大桥”“大桥”这些词对“武汉市长江大桥”做正向最大匹配假设最大词长为5先取“武汉市长江”查词典没这个词就缩短为“武汉市长江”再缩短为“武汉市长”还是没有继续缩到“武汉市”命中了就切分出“武汉市”接着处理剩余字符串“长江大桥”同样从最长开始匹配最终得到“武汉市/长江大桥”。笔试中这个题最常见的变形是“写代码实现”这时候有个细节特别容易出错最大词长的维护。你需要先遍历一遍词典找到最长的词的长度作为max_len而不是拍脑袋定一个5或10。另外切分时要区分边界情况比如空字符串、单个字符、所有词都匹配不上的情况这些都要单独处理。代码大致长这样def forward_max_match(text, word_dict, max_len): words [] i 0 n len(text) while i n: for l in range(min(max_len, n - i), 0, -1): piece text[i:i l] if piece in word_dict: words.append(piece) i l break else: # 词典中无匹配按单字切分 words.append(text[i]) i 1 return words这道题能得满分的关键就是那个else分支。很多人在“匹配不到词”时直接跳过当前字符导致结果缺失正确的做法是当成单字切出来,或者根据题目要求决定怎么处理。反向最大匹配就是从右往左做同样的匹配它有个特性在解决交集型歧义时准确率通常高于正向。笔试中如果问你“为什么反向比正向效果好”答案可以概括为汉语中偏正结构的词占大多数中心词往往在末尾从右往左匹配更容易保留完整的语义单元。关键词提取这一块TextRank也是一个常见考点。TextRank本质上就是PageRank在文本上的应用把每个词看成一个节点词与词之间的共现关系看成边然后迭代计算权重。笔试一般不会让你手写完整的TextRank但可能会问TextRank和TF-IDF的区别是什么为什么TextRank不需要语料库答案的核心就是TF-IDF依赖统计词频和逆文档频率需要有一个文档集合而TextRank只依赖当前文本内部的词共现关系是一种无监督的图排序方法。2.2 BM25相关性打分一道送分题的完整推导BM25在文本挖掘和搜索领域的地位不用多说它几乎是搜索相关性排序的默认基线。笔试中BM25出现的形式有几种直接让你写出BM25公式、给定参数让你计算两个文档的BM25得分、或者问你BM25相比TF-IDF的改进点在哪里。BM25的核心公式如下score(D, Q) sum_i IDF(q_i) * (f(q_i, D) * (k1 1)) / (f(q_i, D) k1 * (1 - b b * |D| / avgdl))其中f(q_i, D)是词qi在文档D中的词频|D|是文档长度avgdl是文档集合的平均长度k1和b是调节参数一般取k11.2到2.0b0.75。IDF部分可以用平滑版本IDF(q_i) ln((N - n(q_i) 0.5) / (n(q_i) 0.5) 1)其中N是文档总数n(qi)是包含词qi的文档数。很多人背过公式但笔试一旦问“为什么BM25比TF-IDF好”就答不上来。关键在于理解TF-IDF的缺陷TF-IDF的TF项是线性的文档里出现10次某个词权重就是出现1次的10倍这会导致长文档天然占便宜而BM25的TF项经过非线性饱和词频增长到一定程度后对分数的贡献增速变缓这更符合实际情况——一个词在文档中出现20次并不意味着它比出现10次重要两倍。还有一个细节是文档长度归一化。BM25引入了|D| / avgdl文档越长分母越大得分会被压低这避免了长文档因为包含更多词而系统性得分偏高的问题。我当年笔试就遇到一道题两个文档一个80词一个160词都包含3次某个查询词问哪个得分高并给出理由。答案就是短文档的得分高因为长文档的词频被长度归一化稀释了。2.3 词向量与主题模型TF-IDF、Word2Vec、LDA的高频问法文本表示是笔试选择题的重灾区。TF-IDF是入门级的词袋模型它把文档变成一个稀疏向量每个维度是一个词值由词频和逆文档频率共同决定。Word2Vec则是把每个词映射成稠密的低维向量通过神经网络训练得到有CBOW和Skip-gram两种结构CBOW通过上下文预测中心词Skip-gram通过中心词预测上下文。笔试常问的点包括Word2Vec两种结构各自的优缺点是什么一般答Skip-gram对低频词更友好CBOW训练速度更快。Word2Vec得到的向量能表示语义吗关键词是“分布式表示”它把语义相似性转化为向量空间的距离但严格来说只是在特定任务中学到的特征表示不一定是真正的“语义”。Word2Vec和Glove有什么区别最简单的一句话回答是Word2Vec基于预测Glove基于全局共现矩阵分解两者在语料利用方式上有本质区别。LDA是文本挖掘方向另一个高频考点。它是一个三层贝叶斯概率模型假设每篇文档是若干主题的混合分布每个主题是若干词的混合分布。笔试问LDA最常见的是问你描述生成过程对每篇文档先采样一个主题分布然后对每个词位置先从主题分布中采样一个主题再从这个主题对应的词分布中采样一个词。这整个过程要能用通俗的话复述出来还知道训练用的方法是吉布斯采样。我备考时发现一个规律笔试很少考深度模型的细枝末节比如BERT的层数、多头注意力的头数反而更喜欢考“你知不知道BERT和传统文本表示的本质区别”。答案是传统方法如Word2Vec得到的是静态词向量一个词在任何语境下都是同一个向量而BERT是动态语境化表示同一个词在不同句子中的向量不同因为它考虑了上下文。这个区别是选择题的高频选项一定要记牢。3. 字符串与通用算法KMP、排序、动态规划的备战重点3.1 KMP的next数组用abacaba把思路捋顺搜索引擎的热词里有一条很醒目“在kmp算法中对于模式串pabacaba其next数组(next[i]定义为...”。这说明KMP的next数组计算确实是校招笔试的经典考题网易这种一线大厂尤其喜欢出。KMP核心思想是当匹配失败时利用已经匹配的部分信息让模式串尽可能向右滑动而不是从头开始匹配。next数组就是这个“已经匹配部分”的量化表达。next数组的定义在不同教材里略有区别最常见的是next[i]表示模式串前i个字符组成的子串中最长相等前后缀的长度。以pabacaba为例我按下标从1开始算给你看i子串最长相等前后缀next[i]1a无前缀后缀长度002ab前缀a后缀b不相等03aba前缀a后缀a相等长度114abac前缀a/ab后缀c/ac/bac都不相等05abaca前缀a后缀a相等长度116abacab前缀ab后缀ab相等长度227abacaba前缀aba后缀aba相等长度33所以模式串pabacaba的next数组是[0, 0, 1, 0, 1, 2, 3]。如果编程时采用下标0开始的写法一般会在开头加一个-1占位得到[-1, 0, 0, 1, 0, 1, 2]两种写法本质一样但写代码时要和你的匹配逻辑保持一致这是我踩过最多次的坑之一。笔试中这个考点还有一种考法给定匹配过程中的某个状态问你模式串应该滑动到哪里。这时候不要去硬背公式直接按“最长相等前后缀”的定义推一遍就行。计算next数组时有个递推技巧已知next[i]的值要算next[i1]只需比较p[i]和p[next[i]]如果相等next[i1]next[i]1如果不相等就递归回退到next[next[i]]继续比较。这个递推写代码就是def get_next(p): n len(p) next_arr [0] * n j 0 for i in range(1, n): while j 0 and p[i] ! p[j]: j next_arr[j - 1] if p[i] p[j]: j 1 next_arr[i] j return next_arr这段代码里最容易出错的是while循环的回退条件。很多新手写成了if而不是while导致匹配失败时只回退一层而不是回退到最长相等前后缀的位置最终结果就是模式串滑动位置错误。3.2 排序算法的复杂度对比基础不能丢分排序算法是选择题里的常客网易笔试题里几乎每年都会出现一道“以下排序算法的平均时间复杂度为O(n log n)的是”或“哪种排序算法是稳定的”这类题目。文本挖掘方向的候选人往往把精力放在机器学习上排序这一块反而容易丢分但实际上它就是送分题把下表记住就够了排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性冒泡排序O(n^2)O(n^2)O(1)稳定选择排序O(n^2)O(n^2)O(1)不稳定插入排序O(n^2)O(n^2)O(1)稳定快速排序O(n log n)O(n^2)O(log n)不稳定归并排序O(n log n)O(n log n)O(n)稳定堆排序O(n log n)O(n log n)O(1)不稳定有几个记忆技巧稳定排序只有冒泡、插入、归并三个其他默认不稳定。空间复杂度超过O(1)的只有归并排序需要额外O(n)的辅助数组快速排序的O(log n)来自递归栈。还要能说出来为什么快速排序最坏情况下退化成O(n^2)每次划分都选到最大或最小元素作为基准导致左右两部分极度不平衡。笔试如果考排序还有一个方向就是“外部排序”针对数据量超过内存的情况。这个在文本挖掘中也很实用比如要对海量文档按某个分数排序内存装不下就要用归并排序的思想先分成多个小块每块内部排序后写入磁盘再做多路归并。回答这类题的关键词是“多路归并”和“败者树”败者树能减少比较次数是比简单多路归并更优的方案。3.3 动态规划与贪心的识别笔试编程题的破题点网易编程题喜欢在动态规划和贪心算法上做文章文本挖掘方向一般不会出特别偏的题常见的模型是最长公共子序列、编辑距离、最大子数组和、背包问题。这些题有一个共同特征就是能用“最优子结构”和“重叠子问题”两个关键词判断出来。我当初准备编程题时最重要的一个技巧是“先判断题型再套模板”。看到题目先问自己三个问题这个问题能否分解成规模更小的子问题子问题的最优解能否组合成原问题的最优解子问题是否会被重复计算如果三个问题的答案都是肯定的那基本就是动态规划直接按“定义dp数组、确定状态转移方程、初始化边界、确定遍历顺序”四步走。举个例子编辑距离是文本挖掘方向很常见的编程题把字符串A转换成字符串B允许插入、删除、替换三种操作求最小操作次数。状态转移方程是如果A[i]B[j]dp[i][j]dp[i-1][j-1]否则dp[i][j]1min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])。这个方程要对三个方向的操作分别理解dp[i-1][j]对应删除A的字符dp[i][j-1]对应插入字符dp[i-1][j-1]对应替换字符。贪心算法则不一样它不需要考虑子问题的组合每一步都做出当前看起来最优的选择而且不回溯。区分动态规划和贪心最快的方法是找反例如果贪心策略在某个场景下得出的不是最优解那这个题大概率是动态规划。最典型的例子是“找零钱”问题如果零钱面额是1、5、11要找15元贪心会先拿11再拿4个1得到5枚硬币但最优解是3枚5元。所以找零钱必须用动态规划而不能用贪心。4. 笔试实操模拟两道典型题目从读题到拿分的完整过程4.1 编程题实战文本相似度计算这里我完整复盘一道我在模拟练习中反复做过的题目题目大意是给定两个由空格分隔的单词序列计算它们的余弦相似度单词向量用词频表示。要求输出保留四位小数的相似度结果。拿到题我建议先不要急着写代码先想清楚整个流程第一步切分两个文本得到单词列表第二步分别统计词频第三步把所有出现过的单词取并集作为特征维度第四步构造两个向量第五步计算余弦相似度。余弦相似度的公式是cos (A·B) / (|A| * |B|)如果分母为0输出0.0000。这里有个关键细节要不要做文本预处理比如去掉标点、转小写。这个要严格按题目要求来题目没说就不要擅自处理很多人在这一步画蛇添足反而丢分。另一个坑是词频统计要考虑词的出现次数而不是简单地判断词是否存在因为余弦相似度用的是词频向量。核心代码可以这样写def cosine_similarity(text1, text2): from collections import Counter words1 text1.split() words2 text2.split() count1 Counter(words1) count2 Counter(words2) all_words set(count1.keys()) | set(count2.keys()) vec1 [count1.get(w, 0) for w in all_words] vec2 [count2.get(w, 0) for w in all_words] dot sum(a * b for a, b in zip(vec1, vec2)) norm1 sum(a * a for a in vec1) ** 0.5 norm2 sum(b * b for b in vec2) ** 0.5 if norm1 0 or norm2 0: return 0.0 return dot / (norm1 * norm2)这段代码能拿满分的关键点有两个一是set构造所有词的并集时不能写成count1.keys() | count2.keys()之外的复杂方式Python里对字典视图用|操作符是合法的但有些笔试环境用的Python版本较老建议先用set(count1.keys())再取并集更稳妥二是分母为0的边界情况如果一个文本为空直接返回0.0。我在实际笔试里还见过这道题的变体要求用JDK中的集合类实现或者限制了不能用现成的统计库。这种时候就要用HashMap手动统计词频逻辑一样但代码会多十几行。建议准备的时候至少手写一遍不依赖Counter的实现避免到了考场上因为环境差异卡壳。4.2 简答题实战设计一个中文分词系统简答题是很多人最没有把握的部分因为它不像选择题有唯一答案。我在准备时给自己定了一个框架遇到“设计一个XX系统”的问题按照“需求-难点-方案-优化”四段式来组织答案既显得思路清晰又能把各种采分点覆盖全。下面以“设计一个中文分词系统”为例看看完整的答题思路。先说需求。中文分词就是把连续的汉字序列切分成有意义的词序列它是文本挖掘的基础。词表从哪来可以基于公开分词词典也可以对领域语料统计生成。难点在哪歧义切分和未登录词识别。歧义指的是“南京市长江大桥”可以切分为“南京市/长江大桥”或“南京市长/江大桥”未登录词指的是词典里不存在的词比如人名、地名、网络新词。再说方案。我会先分三步第一步加载词典并构建前缀词典用哈希表存储每个词及其词频目的是为了让后续的最大匹配和DAG构建能快速查询第二步基于动态规划实现Viterbi算法计算每个位置出现的最大概率路径这里的核心是利用词的联合概率来避免局部最优第三步用隐马尔可夫模型或条件随机场识别未登录词对连续的单字序列重新切分。这个方案的逻辑是先用词典和统计方法处理大部分可识别词再用序列标注模型兜底处理边界案例。最后说优化。还可以聊一聊如何用双向最大匹配结合语言模型打分或者引入领域词典来提升垂直场景的表现。简答题最忌讳的是只写方案不写理由我给自己定的原则是每个方案都要跟一个“因为”比如为什么要用前缀词典因为能高效支持最大匹配中的逐字缩减查询把每次词典查找的时间降到O(1)。5. 备战经验与避坑指南提前批的笔试细节5.1 我踩过的坑答题顺序、环境检查和语言选择先说答题顺序。我的血泪教训是不要按题目顺序从头做到尾。拿到试卷先花两分钟把所有题过一遍把会做的、能拿分的题标出来先做这些再做难题。选择题要控制在每道一分钟以内超过时间先蒙一个不要恋战编程题先做思路最清晰的那道争取一遍通过简答题放在最后因为它耗时最多但分值不一定最高。再说环境检查。网易这类大厂提前批笔试一般用牛客网或赛码网进入考试前有调试环境的时间一定要利用好。我当年就见过一个同学考试开始后发现自己的Python环境里没有安装某个第三方库然后一直在处理环境问题白白浪费了20分钟。牛客网默认的Python环境对第三方库支持并不完整建议全程只用一个语言不要中途切换。考前几十秒先在编辑器里跑一个最简单的print(hello)确认环境能正常执行。关于编程题语言我的建议是如果你不是对C特别熟练优先选Python。笔试编程题重点考察思路和实现并不是工业级性能测试Python的代码量更少出bug的概率更低。但要注意Python的读取输入方式牛客网和赛码网的行输入输出模板最好提前背熟不要到时候现想sys.stdin.readline().strip()怎么拼接。有一个坑特别值得提醒在线评测的编程题输出格式要求非常严格。题目要求输出“保留四位小数”你不能多打空格不能多打换行不能把4.0000输出成4.0。每道题写完都要自己构造一组测试数据跑一遍特别要覆盖边界条件空字符串、单个字符、多个连续空格、最大长度数据。这些边界数据是自己排查出来的比靠评测系统的反馈更可靠。5.2 刷题路线与资料清单一个月从入门到笔试不慌如果你从现在开始准备一个月的时间足够覆盖大部分考点。我的刷题路线分为三个阶段第一周主攻数据结构与基础算法包括数组、链表、栈、队列、二叉树、排序第二周主攻字符串算法和动态规划KMP、Trie树、编辑距离、最长公共子序列是重点第三周主攻机器学习和文本挖掘专项TF-IDF、BM25、Word2Vec、TextRank、LDA都要能手推公式第四周全真模拟用往年大厂笔试真题练手掐时间做练习时间分配。推荐的题目来源力扣上的“字符串”标签下的中等难度题已经够用尤其是Implement strStr()、Longest Common Prefix、Edit Distance这几道几乎是笔试原题。再加上一些专门针对校招的题库上面能搜到大量“网易笔试”标签下的题目虽然不一定是真题但出题风格非常接近。机器学习部分不需要背太深但基础公式一定要滚瓜烂熟朴素贝叶斯的后验概率计算、逻辑回归的损失函数和梯度下降、SVM的优化目标、KMeans的算法流程、PCA的降维原理。选择题喜欢在“算法的时间复杂度是多少”“哪个算法的损失函数是什么”这类问题上做文章。文本挖掘专项部分我最常用的一张表是“模型对比表”把模型名称、类型、是否需要标注数据、输入输出、缺点列在一起对比记忆考前半小时过一遍非常高效。最后说一个自学党特别容易忽略的点提前批笔试的投递时间往往比正式批早一两个月想去网易这类公司的最晚大三下学期就要开始关注官网和内推信息。很多人觉得提前批离自己很远等报名系统开放了才发现准备时间只剩两周那只能硬着头皮上心态就容易崩。提前批的优点是不影响正式批就算笔试没过后续还是可以正常投递所以有条件的一定要参加用它练手也好。我在实际准备过程中最大的体会是笔试并不需要你掌握多么前沿的知识它考验的是基础扎不扎实、边界情况考虑得全不全、时间分配合理不合理。文本挖掘算法工程师这个岗位笔试考的很多内容看起来和“文本挖掘”关系不大但背后考察的是一个工程师能不能在限定时间内把问题想清楚、用代码实现出来、并用文字表达出来。这三项能力才是校招笔试真正想筛选的东西。最后再分享一个小技巧临考前一天不要再刷新题了把整理过的公式表、算法模板、易错点翻一遍然后好好睡觉。笔试拼的既是实力也是状态思维清晰比多刷十道题更重要。