那年校招季,我在电脑前点开唯品会2018校招数据结构的笔试链接,A卷的时限是九十分钟。说实话,做之前我以为会是网上流传的那种"大小堆求中位数""手写红黑树"之类的硬核题,真正把卷子从头到尾过了一遍之后,我的感受是:这套题并不偏难怪,但它非常"刁"。刁的地方在于,它不怎么考你背没背过某个冷门算法,而是考你在有限时间内,能不能用最扎实的数据结构基本功,把一道看似普通的题做对、做快、做完整。
唯品会作为电商平台,业务场景里天然带着"高并发读、海量商品、实时推荐、订单状态流转"这些关键词,所以它的数据结构笔试题,并不像纯算法竞赛那样追求奇技淫巧,而是更看重你对基础数据结构的理解深度、边界条件意识,以及把结构与实际场景挂钩的能力。这篇文章我把A卷涉及的核心考点、我当时踩过的坑、以及对每一类题目的复盘思路整理出来,给后面准备电商类校招笔试的同学做个参考。不管你是刚把《数据结构》教材翻完的在校生,还是刷题量已经上去但总在笔试环节差一口气的求职者,这篇文章都值得你花十分钟认真读完。
下面我按照A卷实际涉及的知识模块,从具体题目类型入手,把考察意图、解题思路和易错点一次说透。
1. 笔试的整体气质:九十分钟里的"陷阱"与"分水岭"
先说说这套A卷给我的整体观感。整张卷子分成了客观题和编程题两大块,客观题以选择题和填空题为主,覆盖了复杂度分析、线性表、树、图、查找、排序这些常规章节;编程题是两道手写代码题,一道偏重链表操作,一道偏重二叉树遍历。
为什么要强调"观感"?因为校招笔试题的区分度并不全在最后两道编程大题上。像唯品会这种体量的公司,笔试环节要筛掉的人远多于能进入面试的人,所以客观题里埋了大量"看起来会、细想就错"的陷阱。我印象很深的一道选择题:
在一个长度为 n 的顺序表中,在第 i 个元素之前插入一个新元素,需要向后移动多少个元素?
很多人一眼扫过去,觉得答案是 n - i,实际上顺序表插入的标准表述应该是"移动 n - i + 1 个元素"。注意,题目说的是"在第 i 个元素之前插入",如果 i 从 1 开始计数,那第 i 个元素到第 n 个元素都要往后挪,一共是 n - i + 1 个。这个 +1 就是命题人留的分水岭,基础不扎实的同学,这里就被划走了。
再比如另一道关于循环队列的填空题,给定了队头指针 front 和队尾指针 rear,问队列长度怎么算。背过公式的人都知道是 (rear - front + maxSize) % maxSize,但题目里把 maxSize 换成了数组容量 m,然后 rear 和 front 的初始关系给的是"队尾指针指向队尾元素的下一个位置"。两个条件叠加,很多同学就开始懵。这类题目本身不难,难在你能不能在不同的表述方式里,准确识别出它考察的其实是同一个知识点。
这一部分我复盘下来的核心结论是:校招笔试题里的数据结构客观题,本质是在考"概念的精确性"和"边界条件的敏感度"。你光知道"顺序表插入要移动元素"是不够的,你得知道确切移动多少个;你光知道"二叉树中序遍历是左根右"也是不够的,你得知道当树的存储结构换成线索二叉树时,前驱和后继指针该如何判断。
2. 链表类题目:唯品会笔试的高频主角与递推陷阱
链表几乎是所有校招数据结构笔试题里跑不掉的主角,唯品会A卷也一样。选择题里考了单链表的插入、删除操作的时间复杂度,编程题里有一道是"反转从位置 m 到 n 的链表"。这一节我重点聊聊链表这一块,因为它在选择题和编程题里的出现方式完全不同,需要分开拆解。
2.1 选择题里的链表:操作步骤与指针指向
A卷选择题里有一道非常经典的题:在单链表中,已知指针 p 指向某个结点,要在 p 之后插入一个新结点 s,正确的操作顺序是什么?
这个题的标准答案相信大家都背过:s->next = p->next; p->next = s;先让 s 的指针域指向 p 的后继结点,再让 p 的指针域指向 s。但如果你只是背了答案,碰到变体题就容易翻车。唯品会这道题的变体在于,它把"在 p 之后插入"换成了"在 p 之前插入",而且没有给头指针,只给了 p 指针。单链表是没有办法直接找到前驱的,这题的答案就不是简单的调整两个指针了,而是要借助"偷天换日"的思路:把 s 插入到 p 的后面,然后交换 s 和 p 的数据域。这种考法,比单纯背代码更能看出一个人是不是真的理解了链表的物理结构。
再来看一道考察链表删除的选择题:删除单链表中 p 指针所指向结点的后继结点。这个比前面那道更基础,但依然有同学会选错。标准操作是先定义一个临时指针 q 指向 p->next,然后让 p->next = q->next,最后释放 q。容易出问题的地方在于,如果题目把"释放 q 的内存"写成了"释放 p 的内存",你还能不能一眼看出来?这类题目在A卷里反复出现,其实是在提醒你:纸上写代码不是写给自己看的,是写给机器跑的,每一个指针的指向都必须落到实处。
2.2 编程题里的链表:反转区间链表的完整解法
A卷的编程题里,链表的题目是"反转从位置 m 到 n 的链表,要求只遍历一次"。这道题如果你只会反转整个链表,是很容易在区间边界上翻车的。
我在考场上用的解法分三步:
第一步,找到第 m-1 个结点,记为 pre。这一步骤要注意,如果 m=1,那么 pre 就是 null,这种情况下头结点会变,需要特殊处理。
第二步,在 m 到 n 的区间内执行标准的头插法反转。这一步的关键是记住,每次把当前结点 cur 的下一个结点 temp 摘下来,插到 pre 的后面,然后 cur 继续向后走。
第三步,处理边界。如果 pre 是 null,新的头结点就是反转后的区间第一个结点;如果 pre 不是 null,就把 pre 的 next 指向反转后的第一个结点。
这是我当时写的核心代码,我把它整理成了可运行的版本:
struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(NULL) {} }; ListNode* reverseBetween(ListNode* head, int m, int n) { if (head == NULL || m >= n) return head; ListNode dummy(0); dummy.next = head; ListNode* pre = &dummy; for (int i = 1; i < m; i++) { pre = pre->next; } ListNode* cur = pre->next; for (int i = m; i < n; i++) { ListNode* temp = cur->next; cur->next = temp->next; temp->next = pre->next; pre->next = temp; } return dummy.next; }这段代码里有两个点值得多说一句。一是 dummy 结点的使用,它让我不用单独判断 m=1 的情况,极大简化了边界逻辑;二是头插法的操作顺序,一定要先把 cur->next 指向 temp->next,再把 temp 的 next 指到 pre->next,最后更新 pre->next。如果这个顺序错了,链表就会断开甚至成环。
这道题在LC(力扣)上有原题,原题编号是92。但如果笔试里碰到,一定要警惕它的变体,比如要求你输出反转后的链表而不是返回头结点,或者要求你不使用 dummy 结点完成同样的操作。变体考的往往不是你会不会反转,而是你对指针操作的理解够不够深。
2.3 链表题的易错点与考后复盘
链表这部分的错误,我复盘了一下,主要集中在三个地方:
- 空指针访问。很多同学在反转链表时,没有判断 cur 和 temp 是否为 NULL,一旦链表长度为边界值,程序直接崩溃。笔试环境里虽然没有编译报错,但面试官看代码时一眼就能发现。
- 丢结点。头插法的过程中,如果没有先用临时变量保存 cur->next,那么在修改 cur->next 之后,原来的后续结点就找不回来了。
- 返回值错误。题目要求返回反转后的链表头结点,结果你返回了 dummy.next 但忘了重新赋值 head,或者返回了反转区间的中间结点。
如果你正在准备校招,我建议你在本子上画一遍链表反转的指针变化图,每一步都画出 pre、cur、temp 三个指针的指向。画完你就会发现,这类题真正难的不是"反转"本身,而是"在反转的过程中如何不丢结点"。这个道理,笔试里用得到,面试手撕代码更用得到。
3. 二叉树与遍历:A卷里的递归与迭代之争
二叉树这一块,A卷考察的密度相当高。选择题里出现了根据前序和中序序列重建二叉树的问题,填空题里考察了完全二叉树的结点编号关系,编程题里则有一道"二叉树层序遍历"的变体。
3.1 根据遍历序列重建二叉树:必考题型与考场思路
"已知某二叉树的前序遍历序列为 ABCDEF,中序遍历序列为 CBAEDF,求后序遍历序列。"这道题是A卷选择题里我印象最深的一道,因为它是典型的"看起来简单,做起来需要耐心"的题目。解题思路其实很固定:前序遍历的第一个结点是根结点,在中序遍历里找到这个根结点,根结点左边是左子树的中序序列,右边是右子树的中序序列;然后根据左右子树序列的长度,把前序序列也分成两段,递归处理。
但考场上的时间压力很容易让人手忙脚乱。我的建议是,在草稿纸上用"分块法"来做,不要在脑子里空转。先把前序序列的第一个字符 A 圈出来,然后把中序序列里 A 左边的 CB 和右边的 EDF 分别框起来,再回到前序序列里数出对应的块 BC 和 DEF。这样一层一层往下拆,后序遍历序列自然就出来了。
这道题考察的实际上是对递归思想的掌握程度。如果你只会用递归做,那笔试是够了;但如果你想在面试里加分,最好能额外掌握迭代做法的思路,也就是用栈模拟递归过程。不过唯品会A卷的笔试阶段,递归解法已经完全够用。
3.2 层序遍历的变体:从"逐层输出"到"之字形输出"
A卷编程题里二叉树那道题,表面上是层序遍历,但加了一个限制:"按之字形顺序打印二叉树,即第一行从左到右,第二行从右到左,第三行再从左到右,以此类推。"这题在剑指Offer里有原题,考察的核心是层序遍历,但多了一个层级方向判断。
我的解法是用双栈法,也就是维护两个栈,奇数层结点先左后右入栈,偶数层结点先右后左入栈。具体来说:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) { vector<vector<int>> result; if (root == NULL) return result; stack<TreeNode*> s1; stack<TreeNode*> s2; s1.push(root); bool leftToRight = true; while (!s1.empty() || !s2.empty()) { vector<int> level; if (leftToRight) { while (!s1.empty()) { TreeNode* node = s1.top(); s1.pop(); level.push_back(node->val); if (node->left) s2.push(node->left); if (node->right) s2.push(node->right); } } else { while (!s2.empty()) { TreeNode* node = s2.top(); s2.pop(); level.push_back(node->val); if (node->right) s1.push(node->right); if (node->left) s1.push(node->left); } } result.push_back(level); leftToRight = !leftToRight; } return result; }这段代码的关键在于,偶数层时要先把右子结点入栈,再把左子结点入栈。这个顺序一旦反了,之字形的效果就出不来。我在考场上就因为这个细节卡了几分钟,还好最后检查出来了。
顺带说一句,如果笔试环境不允许你声明两个栈,用队列加反转数组的方法也能实现。每层正常从左到右入队列,收集完一层的结果后,如果是偶数层就调用 reverse 函数反转后再加入结果集。这种写法在时间复杂度上并没有额外损失,因为每层反转的总代价仍然是 O(n)。
3.3 完全二叉树与堆:隐藏在填空题里的联系
A卷填空题里有一道:一个完全二叉树有 1001 个结点,问叶子结点有多少个。这道题如果不记得公式,可以用"最后一个非叶子结点的下标是 n/2"这个性质来推。完全二叉树中,如果从上到下、从左到右给结点编号,那么最后一个非叶子结点的编号是 n/2(向下取整),所以叶子结点的个数就是 n - n/2。当 n=1001 时,最后一个非叶子结点的编号是 500,叶子结点数量是 1001 - 500 = 501。
这类题整体上不难,但它把二叉树和堆排序联系在了一起。如果你能想到"堆本质上就是一棵完全二叉树",那么很多看似独立的题目,其实背后是同一条知识链。唯品会A卷在这里设置题目,也是在暗示你:数据结构各个章节不是孤立存在的,树和堆、栈和递归、队列和图遍历,它们之间都有千丝万缕的联系。
4. 排序与查找:大数据量场景下的"取舍智慧"
唯品会A卷在排序与查找这一块出的题,是最能体现电商业务特点的。因为它考的并不是"快排怎么写""归并怎么分治"这种默认你会的基础,而是把排序和查找放在具体的场景里,问你"在某种限制条件下,哪种方案更合适"。
4.1 稳定排序与不稳定排序:选择题里的高频陷阱
有一道选择题让我印象很深:下列排序算法中,哪些是稳定的?选项给了冒泡排序、快速排序、堆排序、归并排序、直接插入排序、希尔排序。
这个题如果是死记硬背,很容易搞混。我当时的判断方法是"基于相邻交换"的排序通常是稳定的,冒泡、直接插入、归并都是稳定排序;而"跳跃式交换"的排序往往不稳定,快排、堆排、希尔都是不稳定排序。快排虽然也是交换排序,但它交换的两个元素可能相距很远,所以不稳定。这个判断方法不敢说适用于所有排序算法,但对校招笔试常考的这几种,基本不会出错。
但唯品会的命题人不会让你这么舒服地拿到分。它给出的选项里还有一句描述:"对 nearly sorted 的数组,以下哪个排序算法效率最高?"这道题如果你只记得"快速排序平均时间复杂度最低",就容易掉坑。实际上,对于近乎有序的数组,插入排序的时间复杂度可以逼近 O(n),而快速排序在这种情况下如果不做优化,反而可能会退化到 O(n²)。电商场景里,很多数据都是"每天新增一小部分、大部分保持原序",这种场景下插入排序的实战价值往往被低估。
4.2 海量数据找 Top K:堆排序与快排思想的结合
查找部分最有意思的一道选择题是这样的:在 10 亿个整数中找出最大的 100 个数,内存只有 100MB,问最高效的数据结构是什么。选项里有红黑树、最小堆、哈希表、双向链表。
这道题显然不能直接把 10 亿个数全部装入内存,所以常规的排序算法全部失效。正确思路是维护一个大小为 100 的最小堆,遍历 10 亿个数,每次和堆顶元素比较,如果比堆顶大,就把堆顶替换掉,然后向下调整。这样遍历完一遍,堆里剩下的 100 个数就是最大的 100 个数。时间复杂度是 O(n log k),这里的 k=100,几乎可以看成 O(n)。
这个场景和唯品会"海量商品中找出销量TOP100"的业务需求高度吻合。笔试里考它,其实是在看你会不会把数据结构的知识迁移到真实业务里。如果你只会在教科书上写"堆排序的建堆过程",但不知道堆可以在海量数据里充当"Top K 筛选器",那这道题你就拿不到分。
4.3 二分查找的边界条件:一个让无数人栽跟头的细节
A卷里还有一道二分查找的题,但不是裸的二分,而是给了这样一个场景:"在一个按升序排列的数组中,查找第一个大于等于目标值的位置。"这道题如果直接把标准二分查找的代码写上去,很可能得到的是"任意一个大于等于目标值的位置",而不是"第一个"。
正确的写法是,在nums[mid] >= target时,收缩右边界,同时用 res 记录当前 mid;在nums[mid] < target时,收缩左边界。循环结束后,res 就是第一个满足条件的位置。这种写法本质上是二分查找左边界的问题,它和标准二分查找的区别在于,找到目标值后不是立即返回,而是继续向左搜索,直到找到最左边的那个。
我在复盘时意识到,这类题其实考察的是"二分查找的变体意识"。很多人会写标准二分,但一碰到"第一个""最后一个""插入位置"这些词,就开始凭感觉改代码,改着改着就出了边界问题。应对方法是把二分查找的几种常见变体整理成模板,比如"第一个等于 target 的位置""最后一个等于 target 的位置""第一个大于等于 target 的位置""最后一个小于等于 target 的位置",笔试前每个模板手写两遍,考场上才能稳。
5. 哈希与字符串:电商场景下的隐藏考点
哈希和字符串这两章,在唯品会A卷里不是主角,但出现的题目都很巧妙。它们以选择题和填空题的形式出现,却考出了"你是否理解底层实现"的深度。
5.1 哈希冲突的解决方案:从链地址法到开放定址法
A卷有一道题问:哈希表中解决冲突的方法有哪些?选项里列出了链地址法、开放定址法、再哈希法、建立公共溢出区。这道题没什么难度,但它后面跟了一道小题:"在链地址法中,如果哈希函数设计得不好,导致大量元素映射到同一个桶,此时哈希表的查找时间复杂度会退化成多少?"答案是 O(n),也就是退化成了链表的顺序查找。
这个知识点本身不难,但放到"电商系统里用户ID做哈希取模分库分表,如果某些热点用户ID扎堆,会导致某个库负载特别高"这个场景里,意义就不一样了。唯品会作为电商平台,后端服务里有大量哈希表的使用场景,从缓存到路由表,从消息队列到分库分表,哈希函数设计得好不好,直接影响系统的稳定性。笔试里考这个,说到底是在筛选有工程敏感度的人。
5.2 字符串匹配:KMP算法的最长公共前后缀
字符串部分,A卷考了一道 KMP 算法里 next 数组的填空题:给定模式串 "ababaca",求它的 next 数组。这个题说难不难,说简单也不简单,因为 KMP 的 next 数组有两种不同的定义方式,一种是"最长公共前后缀长度",另一种是"最长公共前后缀长度减一"。如果你用的是严蔚敏教材,next 数组的定义是后者;如果你用的是王道数据结构,定义又是前者。两份教材的 next 数组数值对不上,但 KMP 的整体思路是一样的。
所以我的建议是,笔试前先确认你用的教材是哪种定义,然后把 next 数组的手算方法练熟。以 "ababaca" 为例,如果用"最长公共前后缀长度"的定义,next[0] = -1(或者 0,取决于教材),next[1] = 0,next[2] = 1,next[3] = 2,next[4] = 3,next[5] = 0,next[6] = 1。如果你算出的是另一组数,也不用慌,只要你的 next 数组和模式串匹配时的移动逻辑自洽,笔试改卷通常按关键步骤给分。
值得多说一句的是,KMP 算法在唯品会这种体量的公司笔试里出现的频率并不低,因为电商场景里的敏感词过滤、商品标题匹配、搜索关键词纠错,背后都能看到字符串匹配算法的影子。虽然业务团队不一定真的手写 KMP,但笔试方希望通过这类题,筛选出"学过数据结构并能理解其设计思想"的人。
6. 图的遍历:A卷里最容易被忽略的送分题
说实话,图这一章在唯品会A卷里占比不大,但有一道关于图的遍历的选择题,我觉得值得拿出来说说,因为它也是一道典型的"基础题里藏陷阱"。
6.1 深度优先遍历与广度优先遍历:顺序问题不能想当然
题目是这样的:给定一个无向图的邻接表存储结构,从顶点 V0 出发进行深度优先遍历,以下哪个序列是不可能得到的?
这道题的关键在于,邻接表里每个顶点的邻接点顺序,是由建图时边的插入顺序决定的。如果不考虑邻接表的具体结构,直接按照"字典序最小"去遍历,就很容易选错。我记得当年这道题给出的四个选项里,有两个序列看起来都"像是"从 V0 出发的 DFS 序列,但其中一个违反了邻接表里的实际存储顺序,需要你画出邻接表才能判断。
这类题在教材里很常见,但很多同学平时练习时用的都是邻接矩阵,或者干脆在纸上画图、目测遍历顺序,忽略了邻接表里"边的存储顺序会影响遍历结果"这一关键点。我的经验是,遇到邻接表的遍历题,务必先在草稿纸上把邻接表画出来,再模拟遍历过程,不要凭直觉选答案。
6.2 拓扑排序:入度为零的结点顺序
A卷还有一道拓扑排序的填空题,给了一个有向无环图,要求写出一个拓扑排序序列。这道题本身不难,但我注意到,它考察的方式不是"给你图让你排序",而是"给出一个序列,让你判断它是不是合法的拓扑排序序列"。这就比单纯的生成拓扑排序要难一点,因为你需要对拓扑排序的定义有清晰理解:对于图中的每一条有向边 u→v,u 在序列中的位置必须在 v 之前。
这种"判断合法性"的考法,比"生成"更考验概念的精确性。很多同学会拓扑排序的代码,但你真的给他一个序列,让他逐条边去验证合法性,他反而会犹豫。我当时的做法是,把每一条边都列出来,逐一检查,宁可写慢一点也不要漏掉任何一条边。
7. 考场实战复盘:从审题到代码的完整时间分配
最后这部分,我想完整复盘一下我在做唯品会A卷时的总体时间分配和答题策略,这对你后续参加任何校招笔试都有参考价值。把时间分配讲清楚,比单独讲某一道题更有用,因为它能帮你建立一套属于自己的考场节奏。
7.1 时间分配:选择题快、填空题稳、编程题留足时间
我的策略是:选择题平均每题不超过 1.5 分钟,填空题每题不超过 2 分钟,剩下的时间全部留给两道编程题。
为什么这么分配?因为选择题和填空题考察的是"是否知道",编程题考察的是"能否做到"。知道的题目,你花再多时间也不太可能突然"灵光一现"想到正确答案,所以快速过、标记不确定的题,后面再复查;而编程题需要完整的思路构建、代码书写和边界检查,没有充足时间很容易写出半吊子代码。从我身边同学的反馈来看,翻车的往往不是不会做编程题,而是前面客观题耗时太久,到了编程题只剩二十分钟,只能草草写个思路骗点步骤分。
7.2 草稿纸的使用方法:分块演算与指针追踪
笔试题里的编程题,除非是纯手写代码的纸质考试,一般会提供在线编辑器,但草稿纸依然很重要。我自己的习惯是,遇到链表和树的题目,先在草稿纸上画出结构图,把每一步指针变化都标出来,再往编辑器里写代码。这样做的好处非常明显:很多边界情况,比如头结点变化、空树、只有一个结点,你在图上很容易发现,而在脑子里想就容易忽略。
以"反转区间链表"为例,我在草稿纸上画了三步:先把 m-1 的 pre 标出来,然后从 m 开始,逐个把结点摘下来头插到 pre 后面,最后画出反转完成后的链表形状。画完之后,代码里的指针操作顺序就有了明确的物理意义,写起来几乎不会错。
7.3 复查环节:回看不确定的题目
我大概留了八到十分钟做复查,重点看两类题:一类是之前标记过"不确定"的选择题,另一类是编程题的边界条件。
复查选择题时,我会把题目里的"之前""之后""第几个""是否稳定"这类关键词重新圈一遍,确认自己没有因为看错题目而选错答案。复查编程题时,我会在草稿纸上模拟几组测试用例,比如空链表、只有一个结点的链表、奇数个结点的树、偶数个结点的树。有些边界用例,考场上写代码时很容易忽略,复查环节多花几分钟,往往能挽回好几分。
我现在还记得,当年那套A卷的编程题里有一道关于链表的题目,我在复查时发现自己只考虑了 m=1 的情况,没有考虑 n 等于链表长度的情况。虽然最后两段代码在核心逻辑上是对的,但如果少了这个边界处理,在严格的测试用例下是会出问题的。离交卷还有三分钟时我补上了这个边界条件,那几分大概是救回来了。
8. 备考心法:我不是在教你背题,而是在教你怎么"忘掉背题"
写到这里,我想换个角度,聊聊比具体题目更重要的东西。
你可能已经发现了,这套唯品会A卷,考来考去,核心其实就两件事:一是你对数据结构基础概念的掌握是否精确,二是你能不能把数据结构的技术选型与真实业务场景挂钩。前者靠"背"能解决一部分,但解决不了"第 i 个元素之前插入要移动几个结点"这种扣细节的题;后者靠"刷题"能解决一部分,但解决不了"为什么 Top K 问题要用最小堆而不是最大堆"这种考察理解深度的题。
我个人的体会是,应对这类电商公司的笔试,比刷题更重要的,是把每一个数据结构的"为什么"想清楚。为什么链表插入是 O(1) 而查找是 O(n)?为什么快速排序平均复杂度低但不稳定?为什么哈希表能 O(1) 查找却需要处理冲突?这些问题的答案,才是数据结构笔试真正的考点。
那段时间我把严蔚敏的《数据结构》和王道的《数据结构考研复习指导》对照着看,前者帮我打基础,后者帮我抓考点。我还做了一件事:把每种数据结构的典型应用场景整理成一张表。链表对应 LRU 缓存,栈对应表达式求值,队列对应消息队列,树对应文件系统,堆对应优先队列,哈希表对应缓存系统,图对应社交网络关系。整理完这张表之后,再看到任何"XX场景适合用哪种数据结构"的题目,我基本不需要思考就能选出来。
最后再分享一个小技巧,笔试前一周,不要追求刷难题,而是把教科书上所有的基础代码重新手写一遍。单链表反转、双链表插入删除、二叉树前中后序遍历、层序遍历、快排、归并、堆排、二分查找、KMP、Dijkstra……每个都手写一遍,写的时候留意边界条件。这套动作做完,你的手感基本就回来了。
唯品会A卷的题目本身,到现在已经过去好几年了,但数据结构笔试的底层逻辑并没有太大变化。它依然在用这种方式提醒每一个求职者:基础不牢,地动山摇。希望这篇复盘对你接下来的笔试准备有帮助。