ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

腾讯2023秋招编程题真题复盘与备考指南

腾讯2023秋招编程题真题复盘与备考指南 1. 写在前面为什么腾讯秋招编程题值得反复刷腾讯秋招技术岗的编程题在业界一直有个说法难度不算变态但考察面极广而且非常贴近真实业务场景。和其他大厂动不动就上困难级动态规划不同腾讯的题目更看重候选人“能不能用工程化思维解决实际问题”。我整理了2023年秋季招聘技术岗的编程题合集覆盖了前端、后端、客户端、算法等多个方向。这份合集不是简单罗列题目和答案而是把每一类题背后的考察意图、常见解法、坑点全部拆开讲透。无论你是准备2024届补录、2025届提前批还是单纯想提升编码能力这份合集都能帮你建立起一套应对大厂笔试的方法论。我自己当年参加秋招时吃过不少亏有的题明明会做却因为没处理好边界条件挂掉有的题思路对了却因为时间复杂度不够被卡。这些教训都会在文中逐一标注希望你能避开。2. 秋招编程题的出题规律与备考策略2.1 近三年腾讯笔试的题型分布腾讯技术岗笔试通常包含两个部分客观题选择题和编程题。其中编程题一般是3到5道难度从简单到中等偏上递增考试时间大约60到90分钟。从2021年到2023年的真题来看题型分布有非常明显的规律题型类别出现频率典型考点难度系数字符串处理极高子串匹配、回文、字符串变换中等数组与模拟极高双指针、滑动窗口、排序变种中等动态规划高背包问题、区间DP、状态压缩较难图论与搜索中高最短路、拓扑排序、BFS/DFS中等数据结构设计中LRU、堆、并查集、线段树较难数学与思维中贪心、位运算、找规律不定一个很明显的趋势是纯算法题的比例在下降结合业务场景的“应用题”在增加。比如2023年出现了一道“根据用户观看记录预测下一次点击”的题目本质是字符串匹配但包装成了推荐系统的场景。这就是腾讯的风格——算法源于业务最终回归业务。2.2 从真题反推备考方向刷题不能盲目。如果你只有一个月时间我的建议是优先巩固数据结构基础数组、链表、栈、队列、哈希表、二叉树这六样东西占到了笔试题量的60%以上。2023年合集里至少有3道题直接考察了二叉树遍历和哈希表应用。动态规划抓“背包”和“区间”腾讯笔试的DP题很少出偏题怪题基本集中在01背包、完全背包、最长递增子序列、最长公共子序列这些经典模型上。把这几类搞懂DP题的得分率能到70%。不要忽视模拟题很多人觉得模拟题简单但2023年的笔试里好几道失分严重的题恰恰是“看起来简单、做起来全是坑”的模拟题。比如大数加法、日期计算、矩阵旋转这些题不考算法考的是代码严谨度。练习环境用牛客网或者LeetCode的ACM模式腾讯笔试用的是牛客系统输入输出格式非常关键。我见过太多人因为不熟悉EOF读取、不处理多行输入而白白丢分。2.3 腾讯笔试的计分逻辑与时间分配腾讯笔试的编程题通常按用例得分部分通过也有分。这意味着你不需要追求每道题都AC只要保证能拿分的用例全部拿下就已经超过了大多数竞争者。我的建议分配策略是前2分钟通读所有题目标注出每道题的难度和数据类型范围。先做最简单的模拟题确保基础分入账。再做中等难度的算法题优先选择你最有把握的题解思路。最后处理难题如果剩余时间不足20分钟直接把暴力解写上争取部分用例通过。不要在一道题上死磕超过25分钟。实测下来很多人在某道题上磨了40分钟最后连最简单的题都没时间写这才是最亏的。3. 真题拆解一字符串与模拟类题目3.1 原题重现与思路分析2023年腾讯秋招前端岗有一道经典的字符串题大意如下给定一个只包含小写字母的字符串s你需要将它按照“连续相同字符分组”的规则压缩输出压缩后的字符串。具体规则是如果某字符连续出现次数大于1则用字符次数表示如果只出现1次则直接输出字符。例如aabbbcc压缩后为a2b3c2abcd压缩后为abcd。这道题考察的知识点非常基础字符串遍历 字符计数。但它的得分率并不高原因是很多人在“出现次数为1时不输出数字”这个细节上栽了跟头。我给出的解法是def compress_string(s): if not s: return result [] count 1 for i in range(1, len(s)): if s[i] s[i-1]: count 1 else: result.append(s[i-1]) if count 1: result.append(str(count)) count 1 # 处理最后一组字符 result.append(s[-1]) if count 1: result.append(str(count)) return .join(result) # 测试 print(compress_string(aabbbcc)) # 输出 a2b3c2 print(compress_string(abcd)) # 输出 abcd3.2 容易踩的坑与优化思路这道题最典型的错误有两类边界处理遗漏忘记处理字符串末尾的那组字符。很多人循环结束后直接返回导致最后一组数据丢失。数字拼接错误当连续出现次数超过10时比如连续出现12个a需要输出a12而不是拆开输出。使用字符串数组累加就完全避免了这个问题。这类题虽然简单但腾讯笔试里经常在简单题中混入一两个“陷阱”。比如把输入改成带空格的字符串或者要求压缩后再解压这时候你就需要额外考虑空格、数字字符与字母字符的冲突。如果面试官进一步追问优化你还可以提到使用双指针来实现原地压缩虽然Python里字符串不可变但在C中这可以做到O(1)额外空间。在面试中展示这种思考维度往往是加分项。3.3 举一反三类似的业务场景字符串压缩在真实业务中最典型的应用就是日志数据存储优化。腾讯的很多后台系统每天会产生海量重复日志如果能把相同前缀的日志做压缩能省下不少存储成本。此外腾讯云的对象存储服务在处理上传文件时也会用到类似的“分块去重”机制。你把字符串压缩题练熟了再看这些工程优化方案会有一种“原来是这么回事”的顿悟感。4. 真题拆解二动态规划高频模型4.1 背包问题变种资源分配动态规划是腾讯笔试的大头但2023年系列的难度比往年略有下降更偏向基础模型的变种。下面这道题来自2023年腾讯后端岗某服务器集群有N台服务器处理一个任务需要消耗一定的CPU资源。每个任务的资源消耗为cost[i]完成后产生的收益为value[i]。你可以选择任意数量的任务但总资源消耗不能超过M。求最大收益。这就是一个标准的01背包问题。题目的输入是N和M以及两个长度为N的数组。唯一的小变化是M可以很大达到10^9这时二维DP数组会内存爆炸需要使用滚动数组优化。参考解法#include iostream #include vector #include algorithm using namespace std; int main() { int N, M; cin N M; vectorint cost(N), value(N); for (int i 0; i N; i) cin cost[i]; for (int i 0; i N; i) cin value[i]; vectorlong long dp(M 1, 0); for (int i 0; i N; i) { for (int j M; j cost[i]; j--) { dp[j] max(dp[j], dp[j - cost[i]] value[i]); } } cout dp[M] endl; return 0; }4.2 为什么必须用一维滚动数组很多新手写背包问题时习惯用二维数组但在笔试环境中如果M是10^5甚至更大二维数组会直接导致内存超限。一维滚动数组是必须掌握的技巧。核心逻辑在于处理第i个物品时dp[j]需要从上一轮的dp[j - cost[i]]转移过来。如果j从小到大遍历那么dp[j - cost[i]]可能已经被当前物品更新过了导致同一个物品被重复选取这就变成了完全背包。所以必须让j从大到小遍历确保每个物品只被用一次。这个“为什么倒序”的问题面试官很喜欢在代码 review 时追问你得能讲清楚。4.3 最长递增子序列的两种解法除了背包LIS最长递增子序列也是腾讯的常客。2023年算法岗有一道题给定一个数组求最长严格递增子序列的长度。看似基础但数据范围变成了10^5传统的O(n^2)解法会超时必须用贪心二分优化到O(nlogn)。贪心二分的思路很巧妙维护一个数组tails其中tails[i]表示长度为i1的递增子序列的最小末尾值。遍历原数组时用二分查找找到当前元素在tails中的插入位置更新对应值。import bisect def length_of_lis(nums): tails [] for x in nums: i bisect.bisect_left(tails, x) if i len(tails): tails.append(x) else: tails[i] x return len(tails)这里有个容易搞混的点tails数组本身不一定是合法的递增子序列它只维护“最小末尾值”这个信息。很多人不理解为什么直接替换就行其实关键是tails始终保持有序且长度恰好等于当前已知的LIS长度。我建议你亲手模拟一遍[10, 9, 2, 5, 3, 7, 101, 18]的运行过程走一遍就彻底明白了。5. 真题拆解三图论与实际业务结合5.1 好友推荐与BFS腾讯的核心业务是社交和游戏所以图论题非常喜欢以“好友关系”作为背景。2023年一道经典题是在社交网络中定义两个人的“距离”为最少经过多少条好友关系可以关联到对方。给你一个好友关系列表无向图以及一个固定的起点用户ID要求输出距离该起点为1、2、3...的用户数量。这就是典型的多源BFS不过更准确地说应该是单源BFS逐层扩展。只需要从起点开始BFS记录每个节点所在的层数然后统计每层的节点数即可。参考解法from collections import deque def count_by_distance(edges, n, start): # 建图 graph [[] for _ in range(n 1)] for u, v in edges: graph[u].append(v) graph[v].append(u) dist [-1] * (n 1) dist[start] 0 cnt {0: 1} # 距离为0的只有起点自己 q deque([start]) while q: cur q.popleft() for nxt in graph[cur]: if dist[nxt] -1: dist[nxt] dist[cur] 1 cnt[dist[nxt]] cnt.get(dist[nxt], 0) 1 q.append(nxt) return cnt # 使用示例 edges [(1, 2), (1, 3), (2, 3), (3, 4)] print(count_by_distance(edges, 4, 1)) # 输出 {0: 1, 1: 2, 2: 1}5.2 面试官想看到什么这道题本身不复杂但很多人会忽略几个关键点图可能不是连通的如果某些用户与起点完全隔离它们的距离是无穷大不应该出现在统计结果中。好友关系是双向的忘记建反向边会导致整个BFS路径错乱。节点编号从1开始还是从0开始看清楚输入说明这决定了数组开多大。我见过有人用DFS做这道题虽然也能得到结果但在稀疏图下DFS的递归深度可能会导致栈溢出而且无法自然保证“最短距离”的语义。所以BFS才是正解。面试官想通过这道题考察你能否准确选择最合适的图遍历算法而不是单纯会写递归。5.3 拓扑排序在任务调度中的应用如果说BFS是社交场景的常客那拓扑排序就是后台任务调度的标配。2023年有一道题把这种场景包装得非常真实腾讯文档的协同编辑系统有N个子任务某些任务必须依赖于其他任务完成后才能开始。给定N个任务和M条依赖关系输出一种可行的任务执行顺序。如果存在循环依赖输出空数组。恰好对应拓扑排序的经典算法。关键在于使用队列存储入度为0的节点不断从图中移除它们移除时更新邻居节点的入度重复这个过程。from collections import deque def topo_sort(n, prerequisites): graph [[] for _ in range(n)] indegree [0] * n for a, b in prerequisites: graph[b].append(a) # b - a indegree[a] 1 q deque([i for i in range(n) if indegree[i] 0]) result [] while q: node q.popleft() result.append(node) for nxt in graph[node]: indegree[nxt] - 1 if indegree[nxt] 0: q.append(nxt) if len(result) ! n: return [] # 存在循环依赖 return result实际笔试中你只需要把核心逻辑写对不需要真的模拟一个完整文档系统。但理解业务场景能帮你在面试回答“为什么这样设计”时更有底气。6. 真题拆解四数据结构设计题6.1 LRU缓存的完整实现数据结构设计题是腾讯面试的高频题笔试中偶尔也会出现。2023年有一道题让实现一个LRU缓存Least Recently Used要求get和put的时间复杂度都是O(1)。解决方案分为三步用哈希表存储“键到链表节点”的映射保证查找是O(1)。用双向链表维护访问顺序链表头部是最近访问的节点尾部是最久未访问的节点。每次访问已有节点时把它移动到链表头部每次插入新节点时如果容量超过上限就删除链表尾部节点。class LRUCache: def __init__(self, capacity: int): self.capacity capacity self.dict {} # 使用双向链表预先创建虚拟头尾节点 self.head Node(0, 0) self.tail Node(0, 0) self.head.next self.tail self.tail.prev self.head def get(self, key: int) - int: if key not in self.dict: return -1 node self.dict[key] self._move_to_head(node) return node.value def put(self, key: int, value: int) - None: if key in self.dict: node self.dict[key] node.value value self._move_to_head(node) else: if len(self.dict) self.capacity: oldest self.tail.prev self._remove_node(oldest) del self.dict[oldest.key] new_node Node(key, value) self.dict[key] new_node self._add_to_head(new_node)双向链表的节点定义和四个辅助方法在这里就不贴完整代码了笔试时可以现场推演。关键要记住必须用双向链表单向链表删除尾部节点时无法在O(1)时间内找到前驱节点。6.2 设计题的高分技巧设计题最忌讳一上来就写代码。正确做法是先用5分钟把数据结构图画出来明确每个操作的指针变化再动手。很多同学在纸上画不好链表插入删除硬着头皮写代码结果指针一团乱越改越错。腾讯笔试对设计题的要求是“功能完整 边界正确”至于代码风格是否优美反而不是重点。当然如果你能写出结构清晰、注释得当的代码面试官更容易给你打高分。除了LRU腾讯还考过最小栈、用两个栈实现队列、TopK高频元素。这些题的核心都是“用合适的数据结构组合来解决特定约束”建议每个都亲手实现一遍不要只看题解。7. 真题拆解五数学思维与贪心题7.1 位运算的奇技淫巧腾讯笔试偶尔会出现一些偏数学的问题它们看起来像脑筋急转弯其实考的是对位运算的理解。2023年有一道题是给定一个非空整数数组除了某个元素只出现一次以外其余每个元素均出现两次。找出那个只出现了一次的元素。熟悉的朋友一眼就看出这是经典的“只出现一次的数字”解法是全员异或。def single_number(nums): result 0 for num in nums: result ^ num return result异或运算满足交换律和结合律两个相同的数异或结果为0所以成对的元素全部抵消剩下的就是那个落单的元素。这个解法优雅且高效但很多人第一次看到会一脸懵。如果你在笔试中写出这个解法一定要能解释清楚异或的三个性质否则面试官会怀疑你是背的答案。7.2 贪心策略的证明贪心题更考验逻辑推导能力。2023年腾讯游戏岗有一道题类似这样有N个任务每个任务有一个截止时间ddl[i]和一个持续时间duration[i]。同一时间只能做一个任务求最多能完成多少个任务。这是一个经典的任务调度问题正确策略是按照截止时间从小到大排序用优先队列维护已选任务的持续时间。遍历每个任务时先把当前任务放入队列若当前队列中所有任务的总时长超过当前任务的截止时间则移除持续时间最长的任务。import heapq def schedule_task(durations, deadlines): tasks list(zip(deadlines, durations)) tasks.sort() # 按截止时间排序 q [] total_time 0 for ddl, dur in tasks: heapq.heappush(q, -dur) # 最大堆 total_time dur if total_time ddl: total_time heapq.heappop(q) # 移除最长任务 return len(q)为什么这样是对的因为优先完成截止时间更早的任务是直觉但当总时间超出当前截止时间时我们必然要放弃一些任务。为了最大化任务数量放弃那些耗时最长的任务是最优的。这是一个典型的“反悔贪心”策略。很多人在笔试中能写出贪心算法但问一句“为什么这样贪心是最优的”就愣住了。我建议你自己证明一次交换论证法假设最优解不在这个规则下产生然后通过交换两个任务的顺序构造出更优解推导出矛盾。把这个证明想通了才算是真会。7.3 数学题的边界与溢出陷阱数学题的另一个常见坑是整数溢出。Python里整数可以无限大但C和Java的int只有32位。如果题目范围是10^9加减法还能忍乘法就可能溢出。请一定养成使用long longC或longJava的习惯。腾讯笔试的测评系统经常会设置“大整数边界”的隐藏用例专门用来卡没用64位整数的人。这个问题虽小但一挂就是从AC变成0分。8. 笔试环境与代码实现的实战技巧8.1 ACM模式 vs 核心代码模式很多同学平时刷LeetCode习惯了核心代码模式只需要实现函数但腾讯笔试是ACM模式你需要自己写输入输出。这两者的差异非常大不提前适应会吃大亏。ACM模式下你需要处理多组输入的处理while True配合异常退出。读取一行包含不定数量整数用split切分。输出格式的严格要求比如“每个样例输出一行”或“末尾不能有多余空格”。使用sys.stdin的高效读取方式而不是input()逐行调用。下面是一个典型的ACM输入模板Pythonimport sys def solve(): data sys.stdin.read().strip().split() # 根据实际格式进行解析 it iter(data) n int(next(it)) arr [int(next(it)) for _ in range(n)] # 计算结果 result sum(arr) print(result) if __name__ __main__: solve()用sys.stdin.read()一次性读入所有数据然后按顺序解析速度远超逐行input()。尤其在数据量大的时候两者可以相差数倍。8.2 常用代码模板速查我把自己在笔试中经常用到的模板封装成一套代码模板整理出来供你参考import sys import math import bisect import heapq from collections import deque, defaultdict, Counter # 快速读入 def read_ints(): return list(map(int, sys.stdin.readline().split())) # 并查集模板 class UnionFind: def __init__(self, n): self.parent list(range(n)) self.rank [0] * n def find(self, x): while self.parent[x] ! x: self.parent[x] self.parent[self.parent[x]] x self.parent[x] return x def union(self, x, y): root_x self.find(x) root_y self.find(y) if root_x root_y: return if self.rank[root_x] self.rank[root_y]: self.parent[root_x] root_y elif self.rank[root_x] self.rank[root_y]: self.parent[root_y] root_x else: self.parent[root_y] root_x self.rank[root_x] 1 # 二分查找模板 def lower_bound(arr, target): left, right 0, len(arr) while left right: mid (left right) // 2 if arr[mid] target: left mid 1 else: right mid return left # 二叉树节点定义与层序遍历 class TreeNode: def __init__(self, val0, leftNone, rightNone): self.val val self.left left self.right right这些模板不是让你死记硬背而是让你在紧张的笔试环境中节省思考基础结构的时间把精力留在算法核心逻辑上。9. 腾讯2023秋招编程题的复盘总结与扩展思考9.1 我的亲身踩坑记录我在模拟2023年这套题时至少有三次因为低级失误浪费了大量时间。第一次是背包问题里忘记把容量数组开到M1结果在下标访问时越界整个程序直接崩溃。第二次是拓扑排序时把依赖方向搞反了导致输出的顺序完全错误。第三次是LRU缓存题里我想当然地用了单链表直到动手写删除尾部节点的逻辑时才发现需要前驱指针不得不推倒重写。这些错误都不是“不会做”而是“太急”。笔试现场高压环境下人容易失去耐心凭感觉跳过一些自认为理所当然的细节。我的建议是每道题动手前先在草稿纸上写下三个关键信息数据结构选择、边界条件、输入输出格式。写清楚这三点再开始编码效率会高很多。9.2 从笔试到面试的能力迁移很多同学觉得笔试过了就万事大吉其实笔试中的题目往往是面试官提问的素材。比如你笔试用了BFS做好友距离问题面试官可能会追问“如果图有100亿个节点你该怎么优化”这种时候你需要结合外部存储、分块计算或者改用近似算法来回答。腾讯技术岗面试特别看重“沟通思路”的过程。即使你最终没有写出完全正确的代码只要你能把思路分步骤讲清楚并且主动讨论时间复杂度和空间复杂度面试官通常也会给一个可接受的评价。所以刷题时不要只看正确解法要对每一道题养成追问的习惯还有没有更优解如果数据量大十倍怎么处理如果改成在线查询怎么处理这种思维方式远比刷题数量重要。9.3 后续可以继续深入的方向这份2023年合集里有一部分题跟AI编程工具、低代码平台相关说明腾讯也在关注编程方式的变革。如果你对工程方向更感兴趣可以延伸学习分布式系统中的一致性哈希涉及服务器扩容的场景。RPC框架的负载均衡算法考察加权轮询、最小连接数等策略。存储引擎的LSM-Tree结构与数据库读写放大有关。这些领域未必直接出现在笔试中但理解了它们你在回答很多看似不相关的算法题时会有更宏观的视角。个人来看腾讯秋招编程题的核心不是选拔“刷题机器”而是筛选出那些“逻辑清晰、代码严谨、能快速拆解业务问题”的候选人。希望这份合集复盘能帮你少走一些弯路在接下来的笔试中更有底气。最后再提醒一句动手写亲手跑通每一个用例比看十篇解析都管用。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进