
2023年秋招投智加科技的时候我印象最深的是它的编程题风格——不算偏怪但场景包装得非常“物流”字符串解码、任务调度、网格寻路、货车载重四道题基本把算法笔试里最高频的四类模型都考了一遍。这篇文章把当时整理过的题和解题思路完整复盘一下顺便聊聊自动驾驶公司校招笔试的准备方向。如果你准备的是后续届次的校招或者投的岗位偏向算法、开发应该会有参考价值。1. 智加科技笔试的整体情况与考察方向1.1 笔试形式与岗位差异智加科技做的是重卡自动驾驶业务方向偏干线物流所以校招技术岗主要分成几类感知算法、规划控制算法、软件开发、系统集成等。不同岗位的笔试内容会有差异但编程题部分通常是统一的一套题或者说在同一个题库里抽题。我当时投的是规划控制相关的算法岗笔试在线上平台完成总时长大概90到120分钟除了编程题还有一部分选择题覆盖数据结构、C基础、操作系统和简单的概率题。编程题一般是3到4道难度梯度拉得比较明显。第一题通常是简单到中等给你热身的第二、三题是中等偏上需要你对常见算法模板非常熟练压轴的题会带一点业务背景比如“车队调度”“路径规划”这类场景本质上考的还是经典算法但题目描述会包装成实际业务问题的样子。这是自动驾驶公司笔试的一个共性它想看到你不是只会背题而是能把算法迁移到物流、调度、路线规划这些真实场景里。1.2 四类高频考点背后的业务逻辑我复盘了四道有代表性的题目发现它们其实对应了智加科技日常业务中非常核心的四个技术模块题目类型核心考点对应业务场景字符串解码栈、递归传感器数据解析、通信协议解码任务调度拓扑排序、贪心车队任务编排、算力资源分配网格寻路BFS、最短路AGV仓储调度、局部路径规划货车载重二分答案干线物流装载优化、配载计算这四块恰好覆盖了“感知数据处理—决策规划—执行调度—成本优化”的完整链路。所以备考的时候不要只盯着LeetCode题号刷要带着“这个算法能解决物流场景里的什么问题”去理解面试时如果被问到业务结合也能聊得更深。1.3 编程语言与代码环境的选择笔试平台支持的语言一般有C、Java、Python等。我用的Python原因很直接写快排、BFS这类模板代码比C省时间而且笔试环境里Python的输入输出处理只要用对input()和sys.stdin速度也够用。但如果你对C模板更熟建议坚持C很多自动驾驶公司的底层代码是C面试官对C功底会更看重。有一点需要注意Python在笔试里的set、dict、deque这些内置容器非常能救命但别在循环里频繁用list.pop(0)复杂度是O(n)数据量一大就会超时。正确做法是用collections.deque的popleft()。这类细节后面复盘题目时会具体提到。2. 真题复盘字符串解码与任务调度2.1 字符串解码嵌套展开与栈模拟题目描述大概是这样的给定一个编码后的字符串规则是k[encoded_string]表示方括号内的字符串重复k次嵌套可以有多层。比如3[a2[c]]解码后是accaccacc输入保证括号是合法匹配的要求输出解码结果。这道题是经典题的变体核心思路是栈模拟。遇到数字时累加得到真正的重复次数遇到左括号时把当前字符串和数字压栈进入新一层遇到右括号时弹栈并拼接字符串。我用的是两个栈一个存数字一个存字符串。def decode_string(s: str) - str: num_stack [] str_stack [] cur_num 0 cur_str for ch in s: if ch.isdigit(): cur_num cur_num * 10 int(ch) elif ch [: num_stack.append(cur_num) str_stack.append(cur_str) cur_num 0 cur_str elif ch ]: repeat num_stack.pop() prev_str str_stack.pop() cur_str prev_str cur_str * repeat else: cur_str ch return cur_str踩坑点有两个。第一数字位数可能不止一位比如12[a]必须用cur_num cur_num * 10 int(ch)来累计不能只处理个位数。第二cur_str在遇到]之前可能已经积累了当前层级的普通字符弹栈拼接时要把之前的结果放在前面才能保证嵌套顺序正确。这道题还有递归解法思路是遇到数字就递归解析子串遇到]就返回。递归写起来更直观但笔试环境里如果用例嵌套特别深Python默认递归深度可能会爆所以栈模拟是更稳的选择。2.2 任务调度有依赖关系的执行顺序问题第二道题比较有意思题目描述了这样一个场景一个车队有N个维护任务编号0到N-1每个任务需要 t[i] 时间完成任务之间可能有依赖关系——比如任务b必须等任务a完成之后才能开始。车队有足够多的执行单元可以同时执行任意多个互不依赖的任务问完成全部任务的最短时间。这题其实就是DAG上的关键路径问题标准解法是拓扑排序加动态规划。每个任务的最早开始时间是所有前置任务完成时间的最大值自己的完成时间等于开始时间加上耗时最终答案是所有任务完成时间的最大值。from collections import deque def earliest_finish(n, times, deps): graph [[] for _ in range(n)] indeg [0] * n for a, b in deps: graph[a].append(b) indeg[b] 1 q deque([i for i in range(n) if indeg[i] 0]) start [0] * n finish [0] * n while q: u q.popleft() finish[u] start[u] times[u] for v in graph[u]: start[v] max(start[v], finish[u]) indeg[v] - 1 if indeg[v] 0: q.append(v) return max(finish)复盘的时候我提醒自己注意三点。第一题目给的任务编号如果是1-based读入后要减1不然数组越界会直接跑挂。第二多个分支汇合的任务开始时间必须取所有前置完成时间的最大值不能简单累加因为并行执行时前置任务本来就是同时进行的。第三如果图里有环拓扑排序的队列会提前结束这时候可以用一个计数器判断是否遍历完了所有节点没有遍历完就说明存在依赖环需要特殊处理。这道题对应的业务场景太明显了自动驾驶车辆在途运行时有多个维护任务比如模型更新、数据回传、电池检测这些任务有依赖关系调度系统要算出最短的维护窗口。理解了这个背景题目读起来就不会觉得是纯抽象图论题。3. 真题复盘网格寻路与货车载重3.1 网格最短路径BFS套路的边界处理第三题是典型的网格BFS。题目大致是一个N乘M的网格仓库0表示可通行1表示障碍物一辆AGV从左上角出发每次可以上下左右移动一格不能出界也不能进障碍物求到右下角的最少步数不可达输出-1。核心解法就是广度优先搜索第一层到达终点时一定是最短步数因为BFS按层扩展天然保证最短。from collections import deque def min_steps(grid): n, m len(grid), len(grid[0]) if grid[0][0] 1 or grid[n-1][m-1] 1: return -1 dirs [(1,0), (-1,0), (0,1), (0,-1)] q deque([(0, 0, 0)]) visited [[False] * m for _ in range(n)] visited[0][0] True while q: x, y, step q.popleft() if x n-1 and y m-1: return step for dx, dy in dirs: nx, ny x dx, y dy if 0 nx n and 0 ny m and not visited[nx][ny] and grid[nx][ny] 0: visited[nx][ny] True q.append((nx, ny, step 1)) return -1这里有两个很常见的坑。一是在入队时就标记visited而不是出队时再标记否则同一个节点可能被多次加入队列在大地图上会指数级增加计算量甚至超时。二是起点或终点本身就是障碍物时要提前返回-1我当时差点漏掉这个边界。这道题还有进阶版本如果网格里的不同区域有不同的“通过代价”那么BFS就不适用了要换成Dijkstra利用优先队列按代价从小到大扩展。智加科技的笔试如果加难度通常会把这类题改成带权寻路所以备考时把BFS和Dijkstra一起复习会比较稳。3.2 最小最大载重二分答案的经典问法第四题是压轴题考的是二分答案。题目场景是物流节点有N件包裹重量分别为w[i]现在要按照原顺序装到M辆货车上每辆货车至少装一件要求所有货车中最大载重尽量小问这个最小的最大载重是多少。这道题本质上是“把数组按顺序分割成M段使最大段和最小”。直接求很难下手但换个思路就很简单如果给定一个载重上限cap我们贪心按顺序装看需要几辆车如果需要的车数不超过M说明cap是可行的可以试试更小的cap否则就增大cap。这个“可行性判断”是O(n)的整体用二分答案复杂度是O(n log sum)。def can_split(weights, m, cap): cnt 1 cur 0 for w in weights: if cur w cap: cnt 1 cur w else: cur w return cnt m def min_max_load(weights, m): left max(weights) right sum(weights) while left right: mid (left right) // 2 if can_split(weights, m, mid): right mid else: left mid 1 return left二分下界的设置很关键left必须从max(weights)开始因为单件的重量不能拆分任何一辆车的载重至少能装下最重的那件包裹。上界取所有重量之和就够因为一辆车装下所有货物一定可行。复盘这道题我强调一个细节can_split函数里判断的是所需车数是否小于等于M而不是恰好等于M因为carry容量允许浪费能用更少的车当然更优。另外如果M大于N也就是车比货还多这种情况通常题目会保证不出现但万一出现直接返回max(weights)即可。二分答案这个模板在很多物流题目里都能套比如“在D天内送达包裹的能力”“分割数组的最大值”“每个工人最多能搬的重量”等等。建议把这类题整理到一起看理解“可行性判断—二分区间”的套路比单独背一道题有用得多。4. 考场作答中的常见失误与提分细节4.1 输入输出格式导致的非技术扣分编程题最常见的翻车点不在算法本身而在输入输出处理。很多同学刷LeetCode刷习惯了核心函数能写出来但一到笔试平台的ACM模式就不知道怎么读数据。笔试时一定要先看清楚输入格式。比如第一行是N和M第二行是数组还是要循环读完所有行。我当时的习惯是先把所有输入一次性读进来用split()切分然后按顺序解析不要在读取时做复杂的逻辑判断。用sys.stdin.read()配合split()比反复调用input()快得多数据量大时能省下不少时间。还有一个很坑的地方有些平台要求最后输出结果不带多余空格或换行这个通常不会卡判题但如果你多打了一行日志输出就会导致格式错误。所以调试用的print在提交前一定要删干净或者用专门的调试变量控制别把调试信息混进正式输出。4.2 超时与内存越界的排查思路如果提交后报超时别急着优化算法先检查是不是有死循环或者无效遍历。我当时在第一题上浪费了一点时间就是因为没有用visited数组导致BFS在环形路径上反复进队。排查的顺序是先看边界条件是否会导致无限循环再看是否有重复计算最后才考虑换更优的算法。内存越界和数组越界在C里是直接报错或崩溃Python里通常不会立刻暴露而是以Runtime Error的形式出现。遇到这种情况重点检查数组下标是否可能等于长度尤其是在处理边界格子、最后一个元素时。我的经验是在写完代码后对着边界值手动跑一遍比如N1、M1、数组只有一个元素这种极端用例最能暴露问题。4.3 时间分配先拿基础分再攻难题三个小时内做完所有题不是唯一目标拿到尽可能多的分数才是。我的策略是先把四道题都快速扫描一遍从最简单的那道开始写确保能过的用例一定过掉再回头啃难题。第一题和第二题属于必须拿满分的范围第三题如果BFS模板熟练也能拿满分第四题即使二分答案没完全调通把暴力解写出来也能拿部分分。笔试评分通常按通过用例的比例给分所以不要因为某道题没写出最优解就直接空着。哪怕是暴力枚举只要时间允许也要写上去。很多情况下部分通过的分数比零分好太多了。5. 面向自动驾驶赛道的算法准备建议5.1 刷题范围怎么划我复盘完这四道题之后最大的感受是自动驾驶公司校招笔试的题目并不追求偏题怪题而是集中在几个“未来业务一定会用到”的算法类型上。准备的时候可以按这个优先级来划分范围。第一梯队是数据结构基础数组、链表、栈、队列、哈希表这些是写一切算法的地基。第二梯队是高频算法模板BFS/DFS、二分答案、滑动窗口、双指针、前缀和、并查集其中并查集在感知目标关联里经常出现。第三梯队是图论进阶拓扑排序、Dijkstra、最小生成树对应调度和路径规划场景。第四梯队才是动态规划校招笔试里DP出现的频率没有前几类高但一旦出现就是中高难度比如背包问题、状态压缩DP最好也要能写基础版本。LeetCode刷题建议按“题型”来刷而不是按题号顺序刷。比如“二分答案”专题里把“分割数组的最大值”“在每个水果分配中最小化最大数量”“D天内送达包裹的能力”放在一起对比你会很快发现它们的check函数思路高度相似。这种归纳式的刷法比盲目刷300道题效率高很多。5.2 如何把算法题和业务场景结合起来智加科技这类公司的笔试题目喜欢把算法包装成业务场景这其实是个信号比起单纯招一个“会刷题的人”他们更希望招一个“理解业务问题并能建模”的人。我建议准备面试的同学在刷题时多问自己一个问题这个算法放在自动驾驶卡车业务里能解决什么真实问题BFS是局部路径规划的基础Dijkstra是全局路径规划的经典方案拓扑排序对应任务依赖调度二分答案能算装载优化和能耗分配。面试时如果被问到“你熟悉哪些算法”不只是报菜名而是能把算法和业务结合起来讲这会是有力的加分项。还可以顺带了解一些行业知识自动驾驶卡车在干线物流中的核心诉求是安全、省油、准时到达所以调度和规划算法在公司内部非常重要笔试题目出这些方向就不奇怪了。这种认知会让你在做题时更有代入感也让你的备考更有方向感。5.3 笔试之外简历与面试的准备视角笔试只是第一关通过之后还有技术面试。编程题答得漂亮只能证明你的代码基本功过关面试官还会追问项目经历和算法原理。我当时在复习笔试的同时把项目里的每一个算法细节都重新过了一遍包括为什么选这个方案、有没有对比过其他方案、性能瓶颈在哪这些问题的准备比刷题本身更花时间。如果你还有时间建议练一下手撕代码就是面试官给一道题你在白板上写完整解法边写边讲思路。笔试和手撕代码的区别还是挺大的笔试可以静下心来写手撕更考验临场表达和代码规范。提前找朋友模拟几轮或者自己开摄像头录屏练习都会很有帮助。总的来说智加科技的编程题难度在自动驾驶公司里属于中规中矩认真准备过算法基础的同学都能应对。真正拉开差距的是对题目的理解深度和代码的稳定性。把这四类题吃透多刷几道同类型的变体笔试这一关不会成为你拿offer的拦路虎。