尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

浩鲸科技校招算法笔试复盘:从数据结构到机器学习核心考点

浩鲸科技校招算法笔试复盘:从数据结构到机器学习核心考点 浩鲸科技2019校招算法类笔试题是很多当年投递通信软件方向校招生的必经一关。这家公司前身是中兴软创主做电信业务支撑系统后来在云计算、大数据、AI方向铺得很开。所以它的算法笔试有个很明显的特点基础题量大、覆盖范围广、编程题偏工程落地不像互联网大厂那样钻极难的动态规划优化但如果不扎实很容易栽在细节上。这篇文章不打算只给一份“答案清单”而是把这份试卷背后真正想考的东西拆开揉碎。我会按照试卷的实际结构把数据结构、经典算法、机器学习、深度学习、编程题五个模块逐一过一遍每个模块挑出最典型的考点讲清楚原理和答题思路最后再分享一些现场考试时真正能救命的经验。不管你是正在准备校招的应届生还是想查漏补缺的从业者这篇都能用得上。1. 笔试整体印象基础题量大覆盖范围广1.1 浩鲸算法笔试的典型结构浩鲸科技2019年的校招算法笔试题整体可以分为三个部分客观题选择填空、简答题、编程题。客观题覆盖数据结构、算法分析、机器学习基础题量在30道左右单题分值不高但容错率低简答题主要考察对经典算法的理解深度比如KMP的next数组怎么求、快排为什么退化、SVM的核函数怎么选编程题通常是两道一道偏字符串处理一道偏动态规划或者排序时间控制在40分钟内比较合理。这个结构其实是很多通信软件公司的通用套路。浩鲸的核心业务是电信BSS/OSS系统数据量大、并发高、逻辑复杂所以它特别看重候选人的基础功底和边界处理能力。它不指望你上来就写出一个工业级分布式算法但你必须把排序、字符串匹配、动态规划这些基本功做到肌肉记忆级别。1.2 这份试卷想考察的三种能力结合试卷整体风格我总结出三个核心考察点第一对算法复杂度的敏感度。电信系统里动辄就是上亿条话单O(n^2)和O(n log n)的差距是分钟级和秒级的差距。所以试卷里会有大量关于时间复杂度的选择题比如堆排序建堆的复杂度、快排最坏情况的触发条件、哈希冲突的解决方案等等。第二对经典算法原理的深度理解。简答题里考KMP的next数组考LRU缓存淘汰策略考二分查找的边界条件这些都是一旦写过源码就能答对、只背结论就会翻车的题目。我在面试中见过太多能背出“快排平均O(n log n)”但写不出partition的候选人浩鲸的题就是专门筛这种“背题党”的。第三工程化的编程能力。编程题不会考那种需要灵光一现的天才题更多是“给定一堆字符串统计出现次数并排序”这类实际工作中天天遇到的场景。但越简单越考验细节输入输出格式、内存占用、排序稳定性这些才是真正拉开差距的地方。2. 数据结构与经典算法客观题里的失分重灾区2.1 KMP算法与next数组那道被反复翻牌的经典题浩鲸这次的客观题里KMP算法几乎必考而且考法很直接“对于模式串pabacaba求其next数组”。这道题我在考场上见过也在后来带新人时给他们出过因为它是检验你有没有真正理解KMP的最佳试金石。next数组的定义以-1为起点next[i]表示模式串前i个字符组成的子串中最长相同前后缀的长度但规定next[0]-1。也就是说next[i]的值等于p[0..i-1]这个子串的最长公共前后缀长度。这里“前缀”不包括整个子串本身“后缀”同理。以pabacaba为例一步步来i子串p[0..i-1]最长相同前后缀next[i]0空--11a无前后缀均为空02ab无03abaa长度114abac无05abacaa长度116abacabab长度227abacabaaba长度33所以最终的next数组是[-1, 0, 0, 1, 0, 1, 2, 3]。这个计算过程笔试时一定要手写一遍再填答案因为很多人会在这里踩一个坑求next[6]的时候脑子里想着abacab的公共前后缀容易顺手写成a长度1但实际后缀ab是和前缀ab匹配的长度是2。这种题考的就是细心和基本功。如果再延伸一点KMP匹配过程中当主串某位置失配时模式串移动到位移 已匹配字符数 - next[失配位置]按next[i]表示p[0..i-1]的最长公共前后缀长度的定义来算。理解了这一点笔试后的大题如果让你模拟匹配过程也能从容应对。2.2 排序算法从复杂度到稳定性的全面考察排序是这份试卷里出现频率最高的考点没有之一。原因很简单BSS系统里到处都要排序按时间排话单、按金额排账单、按优先级排任务排序算法的理解程度直接反映了程序员的基础是否扎实。选择题会考这么几个点哪些排序是稳定的冒泡、插入、归并是稳定的选择、快排、堆排是不稳定的。注意这里有个高频陷阱很多人以为快排不稳定是因为“交换”其实选择排序也交换但选择排序之所以不稳定是因为它会把后面的元素直接换到前面破坏了相对顺序。答题时最好把每个排序的具体执行过程在脑子里过一遍不要只背结论。堆排序建堆的时间复杂度是多少答案是O(n)不是O(n log n)。这个看似简单但很多人答错。原因在于从最后一个非叶子节点开始向下调整时越底层的节点调整次数越少总调整次数趋近于n而不是每个节点都调整log n次。笔试题里专门考这个就是在筛选那些只背“堆排序是O(n log n)”的人。建堆是O(n)之后每次取出堆顶再调整是O(log n)所以整体排序复杂度是O(n log n)但单说建堆阶段是O(n)。快排最坏情况什么时候出现当每次partition选到的基准值都是当前区间的最大或最小值时快排退化成O(n^2)。比如对一个已经有序的数组做快排如果基准值固定取第一个元素那每次划分都极度不均。优化方法是三数取中或随机选基准这个知识点简答题也爱考。我建议备考时自己手写一遍七种常用排序冒泡、选择、插入、希尔、归并、快排、堆排不用跑代码就在纸上把每一趟的数组状态写出来这比刷十道题都管用。排序的三种核心操作——交换、插入、归并——是后面很多算法的基础写一遍能打通很多关联知识点。2.3 经典算法二分、贪心与动态规划的出题套路客观题里还有一批经典算法题难度不大但覆盖面特别广我列几个高频考点。二分查找的边界条件是命中率最高的一题。常见的坑是死循环和越界尤其是当区间只有两个元素时如果mid (leftright)/2取的是左中位数而更新逻辑是leftmid就会死循环。这类题没有捷径必须把“左闭右开”和“左闭右闭”两种写法的边界条件都默写熟练。贪心算法的典型应用比如活动安排问题、哈夫曼编码、找零钱问题简答题常考“为什么贪心策略在这里有效”。答这类题的关键是把贪心选择性质和最优子结构说清楚只说“每次都选结束时间最早的活动”是不够的还要说明为什么这样不会错过全局最优解。动态规划的常规递推比如最长公共子序列LCS、最长递增子序列LIS、0-1背包要么出在选择题让你算某个dp值要么出在编程题让你实现。这类题目我在第4部分会用一个完整案例展开这里先提一个重要结论动态规划不靠灵光一现而是靠“定义状态、写状态转移方程、初始化、确定遍历顺序”四步走任何新题都能套这个框架。3. 机器学习与深度学习算法岗的“分水岭”板块3.1 机器学习基础从LR到SVM的必背结论浩鲸的算法岗笔试机器学习部分占了大概三分之一的篇幅。这跟公司业务有关——电信行业的数据量太庞大了用户画像、流失预警、精准营销都是典型的机器学习落地场景。所以这部分考得非常实务不考推导考结论和理解。线性回归和逻辑回归LR是必考点。要清楚LR虽然名字里有“回归”但本质是分类模型它的输出经过sigmoid函数映射到(0,1)区间可以解释为概率。损失函数是对数损失交叉熵不能用均方误差的原因在于非凸性——如果用均方误差梯度下降很可能陷入局部最优。SVM也是高频考点。重点掌握支持向量是距离超平面最近的那几个样本点核函数的本质是把低维不可分的数据映射到高维空间常用的核函数有线性核、多项式核、RBF核高斯核其中RBF核是最常用的因为它只有一个参数gamma调节起来比较方便。简答题如果问你“核函数怎么选”答案要分层数据量小、特征多优先用线性核数据非线性可分先试RBF如果样本量极大RBF的计算开销会很大这时候可以试试线性核或者改用其他模型。决策树和集成学习是另一大块。要记住C4.5用信息增益比、CART用基尼系数它们的共同目的是解决ID3用信息增益时偏向取值较多特征的缺陷。集成学习的两个流派要区分清楚Bagging如随机森林通过有放回采样降低方差Boosting如XGBoost、LightGBM通过串行训练降低偏差。XGBoost在2019年前后正是最火的时候笔试里出现“XGBoost相比传统GBDT的改进”这类题也不奇怪至少要答出二阶泰勒展开、正则项、列抽样这几条。聚类算法里K-Means几乎必考。它的步骤要能默写随机选K个中心点、分配样本到最近中心、重新计算中心、重复直到收敛。还要知道它的局限对初始中心敏感、K值要预先指定、对非凸簇效果差。K-Means是常见优化方案原理是让初始中心尽量分散。KNN这个算法也值得提一下它虽然简单但却是“懒惰学习”的典型代表——训练阶段不做事预测时才计算距离。它的三个基本要素是K值选择、距离度量、分类决策规则。笔试里如果问你“KNN的三个核心是什么”其实就是这三样。3.2 深度学习从反向传播到CNN的考察重点2019年深度学习已经很热了浩鲸这种有AI团队的公司笔试里一定会有深度学习基础题。但别担心它考不到Transformer那种深度主要停留在经典内容。反向传播是必考题。要知道它的本质是链式法则的反复应用即损失函数对每一层参数的偏导通过从输出层向输入层逐层传递误差来计算。选择题可能会问你“某一层的梯度消失是什么原因”答案是激活函数饱和区导数接近0或者网络层数过深连乘导致梯度趋近0。这引申出一个经典问题为什么ReLU比sigmoid在深层网络中更常用因为ReLU在正值区间的导数为1不会放大也不会缩小梯度有效缓解了梯度消失。CNN的考点很具体卷积操作怎么计算输出尺寸、池化的作用是什么。输出尺寸公式要记牢(输入尺寸 - 卷积核尺寸 2×填充) / 步长 1。池化的作用有三个——降维、增加平移不变性、防止过拟合。笔试里如果出一道“输入224×224×3的图像经过5×5卷积核、步长1、无填充输出尺寸是多少”答案是220×220×卷积核个数闭着眼睛都要能算出来。优化器这块要分清SGD、Momentum、RMSProp、Adam各自的思路。SGD的缺点是收敛慢且容易震荡Momentum通过累积动量来加速收敛、抑制震荡RMSProp对每个参数自适应调整学习率Adam结合了Momentum和RMSProp是实践中最常用的默认选择。简答题如果问“为什么Adam用得多”答案就是它既快又稳对超参数不敏感。3.3 启发式算法粒子群、模拟退火这类“冷门”考点这里必须提一嘴粒子群算法PSO因为它是浩鲸这类公司笔面试里的“惊喜题”。毕竟很多应届生都把精力耗在梯度下降上对启发式算法了解不多而这类算法在工程优化问题中其实很常用——比如电信网络的资源调度、参数寻优都能用粒子群。粒子群的核心思想是模拟鸟群觅食每个解是一个“粒子”有位置和速度两个属性。迭代时每个粒子根据两个最优值更新速度一个是自己历史最优位置pbest一个是整个群体的历史最优位置gbest。速度更新公式是v w×v c1×r1×(pbest - x) c2×r2×(gbest - x)其中w是惯性权重c1是认知系数c2是社会系数r1、r2是[0,1]的随机数然后位置x x v。笔试考PSO不会让你手写完整算法最多是选择题判断“粒子群算法属于哪一类算法”答案是群体智能优化算法和遗传算法、蚁群算法、模拟退火算法一起归入启发式算法。或者出一道简答题问你“如何避免粒子群早熟收敛”可以从增大惯性权重、引入变异机制、增加种群多样性等角度回答。模拟退火算法也是类似考察方式。它的核心是以一定概率接受比当前解更差的解从而跳出局部最优。接受概率通常用Metropolis准则p exp(-(ΔE)/T)其中T是温度随迭代逐渐降低。这个公式在选择题里出现过要记得温度越高、接受差解的概率越大。这些启发式算法的共同特点是“不保证找到全局最优但在合理时间内能找到足够好的解”回答这类简答题的万能句就是这个再配合具体算法的机制说明得分率会高很多。4. 编程题实战三个典型题目的完整复盘4.1 题目一字符串去重并按字典序排序这道题原题记不太清了大意是输入一个字符串去掉重复字符后按字典序升序输出。比如输入cbacd输出去重后的abcd。这道题属于“送分题”级别但却是失分重灾区。原因在于很多人会忽略题目要求的“去重后排序”直接用set去重但set的输出顺序是不确定的如果没有显式排序就会出错。我的标准解法是用一个长度为256的标记数组加排序#include iostream #include string #include vector #include algorithm int main() { std::string s; std::cin s; std::vectorbool seen(256, false); for (char c : s) { seen[(unsigned char)c] true; } std::string result; for (int i 0; i 256; i) { if (seen[i]) { result.push_back((char)i); } } std::cout result std::endl; return 0; }注意这里有个小技巧直接用ASCII码的递增顺序遍历标记数组自然就实现了字典序排序不需要再调用sort函数。如果输入包含中文字符范围要调整但在校招笔试的字符串题里题目一般会说明“输入由小写字母组成”这种情况直接用bool seen[26]更简洁。做题前一定先把题目约束条件看清楚这个习惯比会写代码更重要。4.2 题目二最长公共子序列LCS这题在2019年的笔试里出现过而且当年很多人在状态定义上犯了错。LCS要求的是子序列不要求连续所以不能用滑动窗口必须用动态规划。状态定义dp[i][j]表示字符串A的前i个字符和字符串B的前j个字符的最长公共子序列长度。状态转移方程如果A[i-1] B[j-1]那么dp[i][j] dp[i-1][j-1] 1否则dp[i][j] max(dp[i-1][j], dp[i][j-1])初始化dp[0][j] 0dp[i][0] 0因为空串和任何串的最长公共子序列都是0。这里最容易出错的地方是字符串下标从0开始但dp下标从1开始所以比较时要写A[i-1]和B[j-1]而不是A[i]和B[j]。我见过无数人在考场上因为这个下标偏移而Debug不出来白白浪费时间。用Python写更直观def lcs(a: str, b: str) - int: n, m len(a), len(b) dp [[0] * (m 1) for _ in range(n 1)] for i in range(1, n 1): for j in range(1, m 1): if a[i - 1] b[j - 1]: dp[i][j] dp[i - 1][j - 1] 1 else: dp[i][j] max(dp[i - 1][j], dp[i][j - 1]) return dp[n][m]如果题目要求输出具体子序列需要在计算dp时记录每个转移方向左上方、上方、左方再回溯。但笔试题的编程题通常只要求输出长度所以优先保证核心逻辑正确即可。能写得快、写得对比写出花活重要。4.3 题目三Top K问题——海量数据场景下的必考题浩鲸的业务决定了它很爱考海量数据处理。Top K问题几乎是必考形式是“给定n个数找出其中最大的K个数”。最直接的做法是排序后取前K个复杂度O(n log n)如果K远小于n这种做法在数据量大时会显得很蠢。更好的方案有两个方案一小根堆维护大小为K的堆。遍历数据当堆中元素不足K个时直接插入堆满后如果当前元素大于堆顶就用当前元素替换堆顶然后向下调整。遍历结束后堆里就是最大的K个数。复杂度为O(n log K)空间O(K)。K比较小时效率远高于全排序。用priority_queue实现最方便#include iostream #include queue #include vector std::vectorint topK(const std::vectorint nums, int k) { std::priority_queueint, std::vectorint, std::greaterint pq; for (int num : nums) { if (pq.size() k) { pq.push(num); } else if (num pq.top()) { pq.pop(); pq.push(num); } } std::vectorint result; while (!pq.empty()) { result.push_back(pq.top()); pq.pop(); } return result; }这里的关键点是priority_queue默认是大根堆要取K个最大值必须用std::greaterint反转成小根堆堆顶是堆中最小的元素这样才能把更小的值踢出去。这个细节很多人在笔试时忘记导致整个堆的维护方向反了。方案二快排的partition思想即快速选择。利用partition将数组分成大于基准值和小于基准值两部分如果大于基准值的部分长度刚好是K直接返回如果大于K递归处理那一部分如果小于K则要把右侧元素也拿上。平均复杂度O(n)最坏O(n^2)。笔试时如果要求“时间复杂度O(n)”必须用这个方案但实现起来边界情况多建议现场先用小根堆方案保底有时间再去优化。5. 常见失分点与现场应对锦囊5.1 失分点一只给思路不写复杂度这是我在批改模拟笔试时最痛心的失分点。很多候选人明明算法写得对但忘记标注时间复杂度和空间复杂度白白丢分。笔试题的评分标准里复杂度的正确性占相当比例因为面试官需要快速判断你是否具备算法优化的意识。我的习惯是每写完一段核心代码紧跟一行注释像// 时间复杂度O(n log K)空间复杂度O(K)。这既方便自己检查也方便改卷人给分。5.2 失分点二边界条件考虑不全边界条件是编程题扣分的最大头常见的坑包括空字符串、长度为1的数组、数组元素为负数、K值为0或等于数组长度、整数溢出。我在考场上的习惯是先处理异常分支再写主逻辑把if (s.empty())、if (k 0 || k nums.size())这种判断放在函数最前面然后才开始正常逻辑。这个习惯一旦养成能帮你避开大量隐藏bug。5.3 笔试现场的时间分配建议以浩鲸这份试卷为例总分100分客观题占40分、简答题占30分、编程题占30分。建议时间分配客观题30分钟简答题25分钟编程题35分钟最后留10分钟检查。客观题和简答题不要恋战一道题超过两分钟还没把握就先跳过编程题的分值更重但也不能因为一道编程题卡死而放弃后面的题。先在草稿纸上列出伪代码框架确认逻辑正确再敲代码比边写边想效率高得多。注意笔试题里如果出现“请描述解决思路”这类简答题即使不会写完整代码也要把“算法名称、大致步骤、时间和空间复杂度”这三要素写全混个过程分很容易因为改卷人最关注的就是你有没有算法思维。5.4 考前的最后一周怎么准备这一条是针对还没参加笔试的读者。如果你只剩一周时间我建议不要再去啃新题而是做三件事一是把常见排序、KMP、二分、DP的模板代码手写三遍以上做到肌肉记忆二是把所有笔记整理成一张“复杂度速查表”特别是排序稳定性和常见算法的复杂度这是选择题的送分题三是找两套往年真题严格按考试时间模拟一遍重点锻炼时间分配能力。还有一个容易被忽视的点浩鲸的笔试通常是在线OJ系统输入输出格式和普通IDE不一样如果平时在本地IDE里写惯了cin n到了在线系统有可能连基本输入都搞不定。考前一定要去牛客网或力扣熟悉一下在线答题的输入输出方式尤其是多行输入和以EOF结尾的输入处理。细节决定成败这句话在校招笔试里永远适用。最后再分享一个小技巧我在准备这类通信软件公司笔试时发现一个很高效的复习方法把所有考点拆成一张“考点矩阵”表格横轴是知识点KMP、快排、DP、LR、SVM、CNN等纵轴是考察形式选择题、简答题、编程题然后给每个格子标注自己的熟练度。复习时优先突破“会做选择题但写不出代码”和“能写出代码但说不清原理”这两类因为这两种薄弱项在面试阶段一定会暴露。这张矩阵表直到今天我都还留着工作后带实习生也让他们用同样的方法查漏补缺。浩鲸这份笔试题的难度放在今天来看依然有参考价值至少它让我在毕业后意识到一个事实校招笔试不是考你懂多少高深算法而是考你在压力下能不能写出干净、正确、有复杂度意识的代码。把这个基本功练扎实不管去面哪家公司都不会太慌。
返回列表