
先说点实在的。每年秋招季都有大量同学在后台问我“滴滴笔试到底考什么”“算法题难度如何”“非科班有没有机会”。我翻出早年间整理的2017秋招滴滴出行工程岗笔试真题汇总结合当时多位拿到滴滴Offer的同学的复盘记录重新梳理了一遍。这份材料对于今天准备大厂笔试依然有参考价值——毕竟算法题的考察底层逻辑变化不大变的只是包装方式。滴滴的笔试向来不是“背背八股文就能过”的类型。它带有很强的业务痕迹出行平台、路径规划、订单匹配、并发调度这些场景会直接或间接地出现在题目里。尤其是工程岗笔试通常由两部分组成第一部分是客观题覆盖操作系统、网络、数据库、语言基础第二部分是编程题以算法和数据结构为主偶尔会掺一道系统设计类的开放题。整套题做下来你会明显感觉到滴滴想招的不是“会写代码的人”而是“能解决真实问题的人”。这篇文章我不打算只把题目罗列一遍而是把每类题背后的考察意图、解题思路、常见失分点全部拆开讲透再附上可复现的代码模板和刷题路线。不论你是准备投递滴滴还是想拿这套题检验自己的基础都建议完整看一遍。1. 笔试整体风格与考察逻辑拆解1.1 为什么滴滴笔试偏重算法与业务场景结合2017年滴滴秋招工程岗的笔试在线评测系统上总共3道编程题难度梯度是“易—中—难”外加约20道选择题。和纯互联网公司不一样的地方在于滴滴的算法题里经常藏着“地图”“路径”“订单”“并发”这些出行领域的影子。我举几个那一年实际出现过的题目方向方便你感受风格有一道题是“给定一组经纬度坐标求两个点之间的曼哈顿距离并找出距离最近的一对点”——表面是计算几何/最近点对实际是在模拟“乘客和司机的最短接驾距离”问题还有一道题是“多个司机和多个订单每个司机能接多个订单但每个订单只能分配给一个司机求最大匹配数”——这基本就是把“订单分配”抽象成了二分图最大匹配。这种出题思路背后是有逻辑的。滴滴的核心业务是撮合撮合就得算距离、算时间、算最优分配。笔试官想看到的是你能不能把一个业务问题抽象成数学模型再用熟悉的算法去求解。所以备考滴滴不能只埋头刷LeetCode要在刷题时多问自己一句“这个题在真实业务里对应什么场景”。1.2 题型分布与分值权重参考从当初几个拿到Offer的同学反馈来看2017年滴滴秋招笔试的题型分布大致如下单选题约15-20道覆盖数据结构、操作系统、计算机网络、数据库、C/Java基础每题1-2分。这部分是送分题也是拉开差距的地方。多选题约5道多选少选都不得分难度比单选高容易在“看似都对”的选项里翻车。编程题3道分值大概在40-60分是绝对的拉分项。一道简单题字符串处理或模拟一道中等题DFS/BFS或动态规划一道难题图论或高级数据结构。这里要提醒一句滴滴笔试的客观题部分时间往往不够用。编程题如果卡住了千万别死磕先把能拿的选择题分数拿稳。我见过太多人编程题写不出来最后选择题也没时间检查结果总分被拉低。1.3 笔试环境与语言选择建议滴滴那几年用的是第三方在线评测平台支持C、Java、Python、JavaScript等主流语言。我个人的建议是如果最熟练的语言是C或Java优先选它们Python虽然写起来快但在处理大规模输入、内存受限的题目时有时候会吃亏比如递归深度、运行时间。另外编程题的输入输出格式一定要仔细看。滴滴的题喜欢用“多组测试数据”或“首行输入一个整数T表示测试组数”这种形式不少人挂在输入输出格式上代码逻辑明明是对的结果0分。这个细节我后面会展开讲。2. 高频算法题类型深度解析2.1 字符串与模拟题送分题如何拿满分2017年滴滴笔试的第一道编程题通常是这类。常见考法有字符串去重、括号匹配、版本号比较、IP地址合法性判断、大数相加等。举一个当年类似真题的例子给定两个版本号字符串如“1.2.3”和“1.10.1”逐段比较大小前者大返回1后者大返回-1相等返回0。这道题看起来简单但失分点不少版本号段数可能不同比如“1.0”和“1”需要把缺失的段视作0。每一段可能超过int范围吗可能会但通常控制在int内用stoi或parseInt即可。字符串分割时C的istringstream、Java的split、Python的split(.)都能处理但注意Java的split(.)需要转义成split(\\.)。我当时给同学的建议是这类题不要炫技就用最朴素的分割逐段比较。确保每一段都被转成整数缺失补0然后在循环里比较。复杂度O(n)已经足够。想拿满分关键是“稳”不是“快”。还有一个高频考点是“简化路径”或“解析URL”。这类题考察的是栈的使用——把路径按“/”分割遇到“..”就出栈遇到“.”或空串就跳过其他入栈。注意处理根目录的情况别让栈弹空崩溃。2.2 深度优先搜索与回溯网格类问题的通用解法滴滴笔试的“中档题”里DFS/BFS是常客。真题方向大致有这么几类岛屿数量、迷宫最短路径、单词搜索、矩阵中的最长递增路径。以“岛屿数量”为例给定一个m x n的二维网格其中‘1’表示陆地‘0’表示水域统计岛屿数量。解题思路很固定——遍历每个格子遇到‘1’就计数加一然后通过DFS把相邻的所有‘1’全部置为‘0’或者用visited数组标记避免重复统计。这道题的代码模板我建议写熟def numIslands(grid): if not grid or not grid[0]: return 0 m, n len(grid), len(grid[0]) count 0 for i in range(m): for j in range(n): if grid[i][j] 1: count 1 dfs(grid, i, j) return count def dfs(grid, i, j): if i 0 or i len(grid) or j 0 or j len(grid[0]) or grid[i][j] 0: return grid[i][j] 0 dfs(grid, i-1, j) dfs(grid, i1, j) dfs(grid, i, j-1) dfs(grid, i, j1)这里有一个重要的性能细节DFS在网格很大的时候可能递归深度不够Python默认递归深度约1000所以要么用显式栈要么用BFS要么在递归前sys.setrecursionlimit(10000)。实际笔试中滴滴的数据范围一般不会大到爆栈但如果你用Python最好提前加上递归深度限制。回溯题的经典代表是“全排列”和“组合总和”。滴滴当年考过一道“给定一个无重复元素的数组返回所有可能的排列”这属于标准回溯模板如下def permute(nums): res [] path [] used [False] * len(nums) def backtrack(): if len(path) len(nums): res.append(path[:]) return for i in range(len(nums)): if used[i]: continue used[i] True path.append(nums[i]) backtrack() path.pop() used[i] False backtrack() return res回溯题的难点在于“剪枝”。如果数组中包含重复元素就需要先排序然后跳过“当前元素和上一个元素相等且上一个元素未被使用”的分支。这个细节是高频考点建议专门练几道带重复元素的回溯题。2.3 动态规划滴滴笔试中的压轴常客动态规划是滴滴编程题的重头戏。2017年考过的方向包括最长公共子序列、最长递增子序列、编辑距离、01背包、股票买卖类问题以及带有“网格路径”变种的题目。以“编辑距离”为例给定两个单词word1和word2计算将word1转换成word2所需的最少操作数插入、删除、替换。这道题的DP公式是dp[i][j] min( dp[i-1][j] 1, # 删除word1[i-1] dp[i][j-1] 1, # 插入word2[j-1] dp[i-1][j-1] (word1[i-1] word2[j-1] ? 0 : 1) # 替换或不动 )初始化时dp[0][j]jdp[i][0]i表示空串到非空串需要全部插入/删除。这道题几乎是滴滴笔试或者面试的“老朋友”因为它的状态转移特别能考察候选人有没有真正理解DP的“无后效性”和“最优子结构”。我建议你至少手写三遍而不是只看答案——只有亲手推导过dp表的填充过程遇到变种题比如“只允许插入和删除”或“求具体编辑路径”才不会慌。还有一个方向值得重点准备带权最短路径和动态规划的结合比如“三角形最小路径和”或“矩阵从左上到右下的最小路径和”。这类题虽然简单但滴滴可能会把它包装成“配送员从仓库出发经过多个配送点再返回求最短路径”的样子。底子还是二维DP但换了业务外衣。需要警惕的是如果题目加了“每个点只能经过一次”的条件那就不是DP而是状态压缩DP或TSP问题了复杂度完全不同千万别套错模板。2.4 图论与并查集订单匹配类问题的底层工具2017年滴滴笔试里出现过的“司机订单最大匹配”本质是二分图匹配。但很多同学看到“多个订单分配给多个司机每个司机只能接一个订单”就直接懵了。其实如果你熟悉匈牙利算法或者知道可以把这类问题转化为最大流就能很快做出来。二分图最大匹配的匈牙利算法核心是“增广路”搜索。代码模板邻接表版如下def hungarian(n, m, adj): # n: 左侧节点数司机m: 右侧节点数订单 match [-1] * m def dfs(u, visited): for v in adj[u]: if not visited[v]: visited[v] True if match[v] -1 or dfs(match[v], visited): match[v] u return True return False res 0 for u in range(n): visited [False] * m if dfs(u, visited): res 1 return res除了二分图并查集也是滴滴笔试的高频工具。考法通常是“判断两个节点是否连通”或“求连通分量个数”。比如“给定n个城市和m条道路问还需要修几条路才能让所有城市连通”——这题就是典型的并查集求连通分量数答案等于连通分量数减一。并查集的模板要练到肌肉记忆程度class UnionFind: def __init__(self, n): self.parent list(range(n)) self.rank [0] * n def find(self, x): if self.parent[x] ! x: self.parent[x] self.find(self.parent[x]) return self.parent[x] def union(self, x, y): rx, ry self.find(x), self.find(y) if rx ry: return False if self.rank[rx] self.rank[ry]: self.parent[rx] ry elif self.rank[rx] self.rank[ry]: self.parent[ry] rx else: self.parent[ry] rx self.rank[rx] 1 return True这里“路径压缩”和“按秩合并”两个优化都要写进去缺一个都可能在大数据量下超时。笔试中并查集的题往往不是单独考而是配合Kruskal最小生成树一起出现也就是“给定带权边求最小连通代价”——这个方向也要准备。2.5 单调栈与滑动窗口容易被忽略但常考的技巧2017年滴滴笔试的多选题里出现过与“滑动窗口最大值”相关的题目在编程题里也有一道与“柱状图中最大的矩形”思路相似的变种。这些题的核心是单调栈或单调队列。“滑动窗口最大值”的经典做法是用双端队列维护窗口内的候选最大值保证队列从头到尾递减。代码如下from collections import deque def maxSlidingWindow(nums, k): dq deque() res [] for i, v in enumerate(nums): while dq and nums[dq[-1]] v: dq.pop() dq.append(i) if dq[0] i - k: dq.popleft() if i k - 1: res.append(nums[dq[0]]) return res单调栈的应用场景通常是“找下一个更大元素”“接雨水”“柱状图最大矩形”。滴滴的题目有时候会把“接雨水”包装成“城市积水排放”之类的业务场景但核心算法不变。准备时建议把“单调栈解决最近更大/更小元素”这个模型彻底吃透遇见同类题基本就能秒解。3. 客观题考点操作系统、网络、数据库与语言基础3.1 操作系统进程线程、死锁与内存管理是重点滴滴笔试的操作系统题占比不高但稳定。常考知识点如下进程与线程的区别资源拥有的最小单位是进程调度的最小单位是线程同一个进程内的线程共享地址空间进程之间相互独立。死锁的四个必要条件互斥、占有且等待、不可剥夺、循环等待。题目经常给一个场景问是否可能发生死锁或者考“银行家算法”判断安全状态。虚拟内存与页面置换LRU、FIFO、Clock算法常以计算题形式出现。比如“页面访问序列为1,2,3,4,1,2,5...物理块数为3分别用FIFO和LRU求缺页次数”。进程间通信方式管道、消息队列、共享内存、信号量、Socket。选择题可能会问“哪种方式效率最高”——答案一般是共享内存因为不需要内核态与用户态之间的数据拷贝。我个人认为这类题没什么捷径把《操作系统概念》前几章的核心概念过一遍就够。没必要深挖底层源码笔试阶段考的还是基础。3.2 计算机网络TCP三次握手与HTTP状态码必考网络题是滴滴笔试选择题的固定板块。我翻了下当年的错题整理发现最常出现的是这几类TCP三次握手和四次挥手可能问“第三次握手失败会怎样”或“TIME_WAIT状态出现在哪一端”。TIME_WAIT出现在主动关闭连接的一端持续2MSL这是高频中的高频。TCP与UDP的区别TCP面向连接、可靠、有序、字节流UDP无连接、不可靠、数据报。题目可能会故意说“UDP支持广播”选项正确容易误判。HTTP状态码2xx成功、3xx重定向、4xx客户端错误、5xx服务端错误。2017年滴滴特别喜欢考“301和302的区别”还考过“503 Service Unavailable表示什么”。DNS解析流程从浏览器缓存、操作系统缓存、本地DNS服务器到根域名服务器、顶级域名服务器、权威域名服务器的递归/迭代过程。复习网络时我建议以“一个URL从输入到页面展示发生了什么”为主线把所有知识点串起来。这样不仅应付选择题后面的面试也能用得上。3.3 数据库索引失效与事务隔离级别常见数据库题不算多但每年都有。2017年滴滴笔试考过“什么情况下索引会失效”——比如对索引列使用函数、数据类型隐式转换、LIKE以通配符开头、OR条件中有非索引列等这些都是经典答案。事务隔离级别也是常客读未提交、读已提交、可重复读、串行化。考题往往结合“脏读”“不可重复读”“幻读”来问。MySQL默认的隔离级别是可重复读这一点几乎必考。SQL语法选择题偶尔出现比如“GROUP BY和HAVING的用法区别”或者“内连接与外连接的区别”。如果你平时写SQL不多建议考前把聚合查询和连接查询练一遍不需要太深能做题就行。3.4 语言基础C内存管理或Java集合框架工程岗笔试的语言题取决于你选的岗位语言。选C的话重点看指针与引用的区别、智能指针unique_ptr/shared_ptr/weak_ptr、虚函数与多态、栈内存与堆内存、内存泄漏场景。选Java的话重点看HashMap的实现原理、ConcurrentHashMap的分段锁机制、ArrayList与LinkedList的区别、线程池参数含义。这部分的复习不必上面面俱到聚焦“高频且容易混淆”的知识点即可。比如Java里“HashMap线程安全吗不安全多线程下可能死循环”——这道题在2017年出现过。C里“delete和delete[]的区别”——也出现过。4. 编程题的完整实战演练4.1 真题一合并区间中等难度这是一道当年滴滴笔试中很典型的中等题几乎算LeetCode原题给定一个区间的集合请合并所有重叠的区间。输入样式为4 1 3 2 6 8 10 15 18输出合并后的区间。解题思路非常直接按区间起点排序然后遍历。如果当前区间的起点大于结果中最后一个区间的终点则直接加入否则更新最后一个区间的终点为两者的较大值。intervals [] n int(input()) for _ in range(n): l, r map(int, input().split()) intervals.append([l, r]) intervals.sort(keylambda x: x[0]) res [] for l, r in intervals: if not res or l res[-1][1]: res.append([l, r]) else: res[-1][1] max(res[-1][1], r) for l, r in res: print(l, r)这道题看起来简单但有不少人栽在“输入读取”上。滴滴笔试的输入格式可能有两种一种直接给出区间数量然后每一行是一个区间另一种没有区间数量一直读到EOF。建议在写代码前先看清楚题目描述里的“Input Format”不要默认有数量行。如果题目说“多行输入每行两个整数”那就得用while Truetry/except处理EOF。4.2 真题二拓扑排序的变种较难有一道题让我印象很深。题目大意是给定一组课程的先修关系比如课程B需要在课程A之后修读问能否完成所有课程如果可以输出一种修课顺序。这题的核心就是拓扑排序。思路是建图、统计入度、用队列做BFS。每弹出一个节点把它指向的节点的入度减一入度变为0就入队。如果最终弹出的节点数等于总课程数说明无环可以完成。from collections import deque n, m map(int, input().split()) graph [[] for _ in range(n)] indeg [0] * n for _ in range(m): a, b map(int, input().split()) graph[a].append(b) indeg[b] 1 q deque([i for i in range(n) if indeg[i] 0]) order [] while q: u q.popleft() order.append(u) for v in graph[u]: indeg[v] - 1 if indeg[v] 0: q.append(v) if len(order) n: print(存在环无法完成) else: print( .join(map(str, order)))这道题的难点在于题目可能不会直接给你课程编号而是给课程名称字符串你需要用字典把字符串映射成数字编号。这个“字符串到编号”的转换是一种很常见的预处理手法不只是拓扑排序很多图论题都需要。建议养成“拿到输入先建映射表”的习惯。4.3 真题三最大连续子数组和简单但有变体“给定一个整数数组求一个具有最大和的连续子数组”是经典题Kadane算法就能搞定。但这道题有个变体允许你最多删除一个元素使得剩余子数组和最大求这个最大值。这个变体是2017年滴滴笔试里的一道题很多人在上面失分。核心思路是把状态拆成“未删除元素”和“已删除元素”两种情况来DPnums list(map(int, input().split())) n len(nums) if n 0: print(0) else: dp0 nums[0] # 以当前元素结尾未删除过元素的最大和 dp1 0 # 以当前元素结尾已删除过元素的最大和初始时删除的是第一个元素本身所以和可以为0 res nums[0] for i in range(1, n): dp1 max(dp0, dp1 nums[i]) # 删除当前元素或继续累积 dp0 max(nums[i], dp0 nums[i]) res max(res, dp0, dp1) print(res)这道题的DP状态设计思路值得记下来当题目给了一个额外操作比如删一个、跳一个、改一个往往可以通过增加一维DP状态来覆盖。这个技巧在动态规划里非常通用比如“股票买卖最多两次”也是同一思路。5. 备考策略与刷题路线建议5.1 以真题考点为圆心优先突破高概率题型如果你时间有限比如只剩两周那就别按“从LeetCode第一题刷到最后一题”的思路走太慢了。正确做法是回到真题考点本身把数组、字符串、链表、树、图、DP、贪心这七大类里面的高频题刷透做到看见题目能立刻反应出“这是哪一类、套哪个模板、复杂度多少”。我建议按以下优先级来刷第一优先级字符串处理、数组遍历、二分查找、哈希表应用。题目简单但频率高保证正确率。第二优先级DFS/BFS、回溯、二叉树遍历。中档题主力多做几道培养手感。第三优先级动态规划、图论拓扑排序、并查集、最短路径。难度高但笔试压轴题基本从这类出。第四优先级滑动窗口、单调栈、前缀和。这些是“会者不难”的技巧型题目刷过和没刷过差距巨大。5.2 真题模拟用在线评测训练“一次AC”的能力笔试和平时刷题最大的区别是没有编译器提示错一次就知道在线评测你提交了才知道对不对而且往往不显示全部测试用例。所以平时练习要有意识地训练“一次AC”的能力不能依赖反复提交试错。我自己练过的方法是每道题写完后自己先在草稿纸上模拟几组边界数据比如空数组、只有一个元素、最大值、最小值、大量重复元素。然后检查代码里有没有数组越界、除零、溢出、递归死循环这些问题。如果能在提交前发现并修复那笔试时就会稳很多。一个特别提醒滴滴笔试的编程题部分平台会限制“只能提交一次”或者“多次提交但以最后一次为准”。这两种情况都很坑。所以务必确保代码在本机或本地编辑器上跑通了常见用例再粘贴到在线评测系统。5.3 选择题备考整理错题本比疯狂刷题更有效客观题部分最有效的复习方式不是刷海量题目而是整理“错题本”。我发现很多同学在选择填空题上反复丢同样的分比如“TCP的TIME_WAIT是在主动关闭端还是被动关闭端”“HashMap在并发下为什么会死循环”“索引为什么要遵循最左前缀原则”。这些知识点就是那么二三十个翻来覆去地考。建议的做法是把每次模拟题中做错的题按“操作系统/网络/数据库/语言”四个分类各建一个文档写上题目、错误选项、正确选项、原因分析。考前只需要翻错题本效率极高。5.4 时间分配策略与模拟笔试训练滴滴笔试总时长一般在90到120分钟。合理的分配是选择题30到40分钟编程题剩余时间。如果选择题遇到不确定的不要恋战先选一个最可能的标记下来做完编程题后再回头细想——前提是题目系统支持标记和回看。平时模拟时建议严格按照这个时间安排来练习。很多人第一次参加在线笔试时不适应因为情绪紧张、环境嘈杂、输入法捣乱各种因素导致发挥失常。提前做两三次全真模拟能极大缓解这个问题。6. 常见问题与考场经验6.1 输入输出格式吃不准怎么办这个问题每年都有一堆人吃亏。滴滴笔试平台一般会提供“样例输入/样例输出”但样例往往很简单覆盖不了所有情况。我的建议是不管题目描述里有没有给“T组测试数据”的说明代码都尽量写成“能处理多组输入”的形式。在C里就是while(cinn)在Java里就是while(scanner.hasNext())。另外输出格式也要注意如果要求“每个结果占一行”那最后一行也要换行。有些平台对“行尾空格”不敏感但有些敏感保险起见不要在行尾输出多余空格。6.2 编程题编译错误或超时怎么定位如果在IDE里运行正常粘贴到在线评测系统却编译错误优先检查这几项类名是否为Main、是否漏了import、是否用了Java 8不支持的语法、是否有中文标点混入代码。C选手要检查是否使用了C11特有的特性但平台只支持C98这种情况在2017年的老平台上很常见。超时的话先看数据范围。如果n是10^5级别O(n^2)的算法必然超时要想办法优化成O(n log n)或O(n)。如果n只有100那哪怕O(n^3)也可能通过。拿到题目先看数据范围再决定算法这是笔试最基本的能力。6.3 遇到完全没思路的题怎么办不要空着。很多在线评测平台是“按测试点给分”哪怕是暴力解法只要能在数据较小时通过一部分测试点也能拿到部分分数。千万别因为觉得“我的解法太笨”就不写直接交白卷。一个通用技巧是先把最简单的暴力方案写出来跑通小数据样例保证这套代码能得基础分。如果时间充裕再考虑优化成高效算法。如果你连暴力都想不出来就把样例输入直接打印成样例输出——至少能骗过一个测试点。这招不光彩但总比0分强。6.4 考场心态与防坑经验最后说点掏心窝子的经验。滴滴笔试的题目难度波动很大简单题可能5分钟做完难题可能半小时都没思路。遇到这种情况千万别慌别把时间全部砸在一道题上。先用10分钟把三道题都读一遍形成全局判断哪道题性价比最高哪道题应该放弃。还有一个小技巧编程题如果遇到“大数据量输入”用Python的input()可能超时建议改用sys.stdin.readline()。这看起来是小细节但在数据量为10^5量级时读写速度差异非常明显。我有同学当年就是因为这个细节同样的算法别人AC了他超时。根据我个人经验2017年滴滴秋招笔试整体难度在中上水平比bat的某些部门稍轻松但比普通中小厂难不少。最核心的竞争力反而不是“会多少冷门算法”而是“基础题不丢分、中等题写得快、难题能拿部分分”。如果你能把本文提到的几类真题模板练熟再把选择题的高频考点过一遍通过笔试的把握就很大了。最后再分享一个小技巧笔试结束后赶紧把题目回忆版写下来。滴滴的面试环节经常会追问笔试里的某道题——比如“你当时这道题是怎么写的”“有没有想过更优的解法”。如果你能带着清晰的思路和优化方案去面试会是一个很加分的亮点。