1. 看一份算法笔试卷先看它在筛选什么说到“途虎养车2023秋招算法笔试试卷A”很多准备秋招的同学第一反应是到处找原题、背答案。我做了几年算法工程师也参与过校招笔试出题和面试这里先说一个可能不太中听但很真实的话你几乎不可能拿到某家公司某一年完整的原卷。笔试题目是内部资产流出概率极低网上能搜到的多是零星回忆版。但这不代表这份试卷对你没有参考价值——恰恰相反只要看懂一份有代表性的算法笔试卷在考察什么你就能推出一类公司的出题风格和筛选逻辑。途虎养车做的是汽车后市场业务核心是供应链、门店履约、用户增长、定价补贴、推荐搜索这些方向。这种偏产业互联网的公司算法岗笔试不会像头部大厂那样疯狂堆困难动态规划也不会像纯AI实验室那样上来就考论文复现。它的考察重心通常是数据结构与算法的基础扎实程度、机器学习/深度学习的基础理解、以及把算法落到真实业务场景的工程思维。对于准备这类笔试的同学我的建议是把注意力从“找原题”转移到“拆解考点”上。一份试卷A也好、B卷也好换汤不换药的核心考点就那么几类字符串与KMP、排序与堆、贪心与动态规划、树与图、机器学习基础、优化算法原理。与其焦虑“这份卷子考了什么”不如问自己“如果我是出题人我会用哪些题来区分有没有真实力的候选人”2. 字符串与KMP一道题就能看出基本功2.1 next数组的计算逻辑不能只会背代码在算法笔试里KMP 算法几乎是字符串专题的“钉子户”。很多热搜词里能看到“在KMP算法中对于模式串pabacaba其next数组”这类问题说明这也是高频考点。KMP 的核心不是匹配过程本身而是next 数组的构建是否真正理解。我见过太多候选人能把 KMP 匹配的代码默写出来但一问 next[i] 到底代表什么就含糊了。这里我习惯用一句话解释next[i] 表示模式串前 i 个字符组成的子串中最长相等前缀和后缀的长度通常不包含自身。注意这个“不包含自身”很多人就是栽在这里。拿 pabacaba 举例我们一步步推i0next[0] -1或0看具体实现约定 i1子串a没有真前缀和真后缀相等next[1] 0 i2子串ab前缀a后缀b不等next[2] 0 i3子串aba前缀a后缀anext[3] 1 i4子串abac前缀ab后缀ac不等但前缀a后缀c不next[4] 0 i5子串abaca前缀ab后缀ca不前缀a后缀anext[5] 1 i6子串abacab前缀aba后缀cab不前缀ab后缀abnext[6] 2 i7子串abacaba前缀abac后缀caba不前缀aba后缀abanext[7] 3所以 next 数组是[-1, 0, 0, 1, 0, 1, 2, 3]按 next[0]-1 的约定。笔试里如果出选择题通常会给几组数组让你选如果出编程题就要求你实现getNext()并完成匹配。这里有个实操技巧KMP 的 next 数组有两种主流约定。一种是 next[0] -1另一种是 next[0] 0两者在匹配回退时的下标处理不同。如果你习惯背模板务必在笔试前固定一种写法并反复练习不要考场上临时切换。我在牛客网刷题时习惯用next[0] -1的版本因为匹配时j next[j]的逻辑更统一。2.2 字符串题型的“隐藏考点”与实战选择除了 KMP 本身笔试卷里字符串题还常考最长公共前缀、字符串哈希、回文串Manacher、字典序比较等。这些题单看难度不高但容易在边界条件上翻车。举个实际例子实现strStr()在主串中找模式串第一次出现的位置。暴力法 O(n*m) 在字符串长度上万时就会超时所以 KMP 是标准答案。但有一种更取巧的做法用 Python 的find()一行解决。笔试系统如果允许能过但我不建议依赖这个因为面试追问时你会很难堪。更好的做法是用字符串哈希Rolling Hash把匹配问题转化为哈希值比较配合前缀哈希数组能在 O(n) 内解决而且代码比 KMP 好写很多。字符串哈希需要选好基数和模数我常用的组合是base 131mod 1e97。注意处理哈希冲突时可以双哈希兜底class StringHash: def __init__(self, s): n len(s) self.h1 [0] * (n 1) self.h2 [0] * (n 1) self.p1 [1] * (n 1) self.p2 [1] * (n 1) b1, m1 131, 10**9 7 b2, m2 137, 10**9 9 for i in range(n): c ord(s[i]) self.h1[i1] (self.h1[i] * b1 c) % m1 self.h2[i1] (self.h2[i] * b2 c) % m2 self.p1[i1] (self.p1[i] * b1) % m1 self.p2[i1] (self.p2[i] * b2) % m2 # 注意实际使用时需要分别存储两个哈希的数组 def get(self, l, r): # 计算区间 [l, r) 的哈希值 # 双哈希返回元组降低冲突概率 pass笔试里字符串题的正确策略是优先考虑能 AC 的稳妥方案在足够时间基础上再追求最优解。如果你 KMP 写不熟先用哈希做出来保底拿分比死磕 KMP 导致整题放弃强得多。这是我刷了三百多道题后最深的一个体会——笔试是按通过率给分的部分分也有价值。3. 排序与数据结构堆排序、快排的工程化思考3.1 经典排序算法不只是背诵时间复杂度热搜词里“数据结构排序算法”“堆排序算法”都在前列。排序算法在笔试里出现的形式通常是手写快排/堆排、求第 K 大/第 K 小、排序稳定性判断、自定义比较器。以堆排序为例很多人能背出“建堆 O(n)调整 O(n log n)”但手写heapify时经常出问题。堆排序的核心操作是sift_down下沉而不是sift_up。建堆时从最后一个非叶子节点开始倒着做下沉这个细节不少人会忘。def heapify(arr, n, i): largest i left 2 * i 1 right 2 * i 2 if left n and arr[left] arr[largest]: largest left if right n and arr[right] arr[largest]: largest right if largest ! i: arr[i], arr[largest] arr[largest], arr[i] heapify(arr, n, largest) def heap_sort(arr): n len(arr) # 建堆从最后一个非叶子节点开始 for i in range(n // 2 - 1, -1, -1): heapify(arr, n, i) # 逐个取出堆顶 for i in range(n - 1, 0, -1): arr[i], arr[0] arr[0], arr[i] heapify(arr, i, 0)这里有一个容易被忽略的考点求 Top K 问题时用堆排序的变体维护大小为 K 的小顶堆复杂度是 O(n log K)而用快速选择Quick Select是平均 O(n)。如果题目只要求 Top K 且不要求有序输出Quick Select 更优。但 Quick Select 的缺点是快排 partition 过程容易写错、最坏 O(n^2)所以笔试时我通常先写堆方案保底时间充裕再优化。3.2 排序算法在业务题里的变形笔试里排序通常不是单独考而是作为工具嵌在业务题里。比如“途虎养车有 n 个门店每个门店有若干订单请你按订单量从高到低输出门店 Top 10”——这本质上就是 Top K 稳定排序问题。再比如自定义排序sort(keylambda x: (-x[1], x[0]))这种写法在 Python 里很常见但有些同学对多关键字排序的交换顺序不熟。Python 的 sort 是稳定排序这意味着你可以连续调用两次 sort 实现多级排序但更推荐直接用 tuple 作为 key因为元组比较天然支持多关键字。Java 里则是用Comparator链式调用。我在笔试中见过一个高频业务题变体区间合并。给出一组门店服务半径区间合并重叠区间输出合并后的数量。这题就是先按起点排序再维护当前覆盖终点做贪心合并核心是排序后的一次扫描。这类题考的不是排序算法本身而是“能不能想到先用排序把无序问题变成有序问题”。4. 机器学习与深度学习算法从原理到场景题4.1 KNN、K-Means 与聚类算法的高频考点搜索热词里“knn算法的应用能力包括哪三个方面”“聚类算法”排名靠前。机器学习基础题在算法笔试试卷中占比不低尤其是非纯研究岗。以 KNN 为例常考这么几个点K 值选择K 太小容易过拟合太大容易欠拟合常用交叉验证选取。距离度量欧氏距离、曼哈顿距离、余弦相似度各自的适用场景。特征归一化KNN 依赖距离计算量纲不一致时数值大的特征会主导距离所以必须先标准化/归一化。这三个点不仅是笔试选择题的考点也是场景题的基础。比如题目说“用户画像相似度计算用 KNN 做用户分群特征有年龄、消费金额、浏览时长”你就要反应过来年龄和消费金额量纲不同必须先做标准化同时用户分群更适合用无监督的 K-Means 而不是 KNN因为 KNN 需要标签。K-Means 的考点则集中在K 值怎么选肘部法则、初始中心点怎么选K-Means、收敛条件、对离群点敏感。我在面试中经常追问K-Means 一定能收敛吗答案是能收敛到局部最优但不是全局最优所以需要多次随机初始化取最优结果。这个细节笔试里可能不会直接考但面试会。4.2 深度学习基础激活函数、过拟合与优化器深度学习在笔试里通常不会让你手推反向传播更多是基础概念题。比如Sigmoid 和 ReLU 的优缺点对比、过拟合的解决方案正则化、Dropout、早停、数据增强、常见优化器SGD、Momentum、Adam的区别。这里有个容易混淆的点Adam 一定比 SGD 好吗笔试如果出选择题大概率会问“以下哪个优化器引入了动量概念”答案是 Momentum 和 Adam。但实际工程里Adam 在训练初期收敛快后期容易在最优解附近震荡SGD 配合合适的学习率调度有时泛化更好。我在实际业务模型训练中通常先用 Adam 快速找到一个好的起点再切 SGD 微调。场景题方面途虎这类公司可能出这样的题“用户点击预测模型中正负样本比例 1:99你会怎么处理”标准答法包括过采样/欠采样、调整分类阈值、使用 Focal Loss、评估指标用 AUC/PR 而不是 Accuracy。这类题没有唯一答案考察的是你有没有真正调过模型、踩过数据不平衡的坑。5. 优化算法与场景结合粒子群、模拟退火与PID5.1 启发式算法粒子群和模拟退火的原理与应用看到热搜词里有“粒子群算法原理”“模拟退火算法”“pid算法在crps psu power的作用”说明这批热词背后有相当一部分人在搜索优化算法相关的内容。虽然途虎养车的算法笔试未必会考到粒子群这种相对冷门的内容但作为算法工程师这类优化算法的原理最好还是了解尤其是做供应链排程、路径规划、定价优化时启发式算法是常用工具。粒子群算法PSO的核心思想是模拟鸟群觅食每个粒子是解空间中的一个候选解拥有位置和速度每次迭代根据个体最优pBest和全局最优gBest更新速度与位置。公式是v w * v c1 * r1 * (pBest - x) c2 * r2 * (gBest - x) x x v其中 w 是惯性权重c1、c2 是学习因子r1、r2 是 [0,1] 随机数。代码实现其实只要三十行左右import random def pso(fitness, dim, n_particles30, max_iter100): # 初始化粒子位置和速度 particles [[random.uniform(-10, 10) for _ in range(dim)] for _ in range(n_particles)] velocities [[random.uniform(-1, 1) for _ in range(dim)] for _ in range(n_particles)] pBest particles[:] pBest_score [fitness(p) for p in particles] gBest pBest[pBest_score.index(max(pBest_score))] gBest_score max(pBest_score) w, c1, c2 0.7, 1.5, 1.5 for _ in range(max_iter): for i in range(n_particles): for d in range(dim): r1, r2 random.random(), random.random() velocities[i][d] (w * velocities[i][d] c1 * r1 * (pBest[i][d] - particles[i][d]) c2 * r2 * (gBest[d] - particles[i][d])) particles[i][d] velocities[i][d] score fitness(particles[i]) if score pBest_score[i]: pBest[i] particles[i][:] pBest_score[i] score if score gBest_score: gBest particles[i][:] gBest_score score return gBest, gBest_score模拟退火SA的核心是 Metropolis 准则以一定概率接受更差的解且这个概率随温度下降而减小。它比 PSO 简单但容易调参。笔试题如果出“求函数 f(x) x^2 在 [-5,5] 的最小值”用模拟退火和用梯度下降都能解但概念题更常问SA 跳出局部最优的机制是什么答案是概率接受准则。5.2 PID 控制与工程场景中的算法思维PID 算法出现在热词里有点意外但仔细想也很合理——途虎养车做汽车后市场车联网、智能硬件、门店设备的温控、电机控制等场景都可能涉及 PID。虽然算法笔试考 PID 的概率不高但如果你是做 IoT 方向或汽车相关算法岗PID 就是标配知识。PID 三个环节的作用分别是P比例根据当前误差输出控制量让系统快速接近目标I积分消除稳态误差但积分过大容易超调D微分抑制误差变化速度减小震荡。调参的工程口诀是“先 P 后 I 再 D”我在实际调试温控系统时也是这个顺序先把 P 调到一个临界值系统开始震荡后再加 D 抑制最后加 I 消除静差。从笔试角度如果出一道 PID 相关场景题大概率是“如何让一个温度控制系统更快达到设定值并减少超调”。标准答法无非是增大 P 提升响应速度引入 D 抑制超调精细化调参或使用模糊 PID 自适应。说到底这考的是控制论工程直觉而不是背诵公式。6. 从笔试卷面到真实业务那些刷题刷不来的能力6.1 算法题之外的业务场景题怎么准备回到“途虎养车2023秋招算法笔试试卷A”这个题目本身我虽然拿不到原卷但根据途虎的业务模式可以合理推测试卷里除了纯算法题大概率还有业务场景题。比如如何预测某个城市未来一周的保养订单量时间序列预测 特征工程如何给新用户推荐合适的轮胎/保养套餐召回 排序如何为不同门店分配优惠券预算使得 ROI 最大化约束优化这类题的共同特征是没有标准答案考察的是你把算法问题映射到业务问题的能力。我建议准备时用“问题定义 → 数据选择 → 特征设计 → 模型选型 → 评估指标 → 上线方案”这个框架来组织回答。哪怕你没有实际做过这个业务按这个逻辑说也能让面试官觉得你有系统思维。举个例子订单量预测题我会这样拆问题定义预测粒度是“城市×天”还是“城市×门店×天”这决定数据量和模型复杂度。特征设计历史订单量、星期几、节假日、天气、油价、促销活动、门店数量变化。模型选型基线用 HA历史平均或 ARIMA进阶用 LightGBM 或 Prophet数据量足够再试 LSTM/Transformer。评估指标MAPE、RMSE注意订单量存在明显的周期性MAPE 可能比 RMSE 更合理。上线方案先用离线评估再用 shadow 模式小流量灰度对比线上效果。6.2 刷题建议从“会做”到“做得快、写得对”最后聊聊大家最关心的备考节奏。我当年秋招的刷题量大概在 400 道左右LeetCode 牛客不算多但足够用关键在总结。我的刷题路线是“三阶段法”第一阶段基础期按数据结构分类刷数组、链表、栈、队列、哈希、树、图。每个数据结构至少刷 15 道核心是把 API 和模板题练熟。第二阶段题型期按算法思想分类刷双指针、二分、贪心、动态规划、回溯、DFS/BFS。每类集中刷 15-20 道总结套路。第三阶段模拟期每周 2-3 次完整笔试模拟限时 90 分钟做 3-4 道题刻意训练时间分配。关于时间分配我的经验是试卷发下来先花 3 分钟通读所有题目按“会不会做”分三档。第一档一眼有思路马上写第二档有思路但不确定先写大概率正确的部分第三档完全没思路最后写优先用暴力解或特判拿部分分。不要在一道题上卡超过 25 分钟尤其是编程题后面往往有更简单的题等着你。还有一个容易被忽视的点笔试环境一定要提前熟悉。不同公司用的笔试平台不一样牛客、赛码、猿圈等有的支持本地 IDE 粘贴有的只能在网页上写有的要自己处理输入输出。提前去对应平台做一套模拟题比考前多刷十道题都管用。7. 写在最后算法笔试不是终点而是起点说句实在话我工作几年后再回头看秋招笔试发现那些算法题在真实业务里很少会原样出现。但准备笔试的过程——刷题、总结、复盘——锻炼出来的代码能力、逻辑思维和问题拆解能力是实打实带到工作中的。我现在写一个数据处理 pipeline或者设计一个推荐策略实验用到的基本功仍然是当年刷题时打下的。根据我个人经验最后再分享一个心得笔试前一周不要再疯狂刷难题了把错题本翻一遍把常用模板快排、二分、KMP、拓扑排序、并查集手写一遍比什么都管用。考场上的你拼的不是灵感而是肌肉记忆和稳定的心态。祝准备秋招的各位顺利上岸。