前言
美团算法面试很少考察 Hard 难度题目,出题重心集中在 Medium 题型。虽说题目难度不算顶尖,但是面试官十分看重三点:代码零 Bug、边界条件覆盖完整、时间 / 空间复杂度分析清晰。 高频考点高度锁定五大方向:链表、哈希表、栈、滑动窗口、区间合并。
不同大厂算法考察方向存在明显差异:字节面试 Hard 题占比更高,美团更偏向中等题目的落地实现能力,考察候选人写出健壮可运行代码的基本功。
下面 8 道题目覆盖美团算法面试最高频题型,每一道都包含解题思路、可运行 Java 代码、复杂度分析以及面试官最常抛出的追问。
Q1:反转链表(LeetCode 206)
题目描述:给定一条单链表的头节点,反转整条链表,并返回反转后的新头结点。
迭代解法
使用三个指针 prev、curr、next 遍历链表;每次断开当前节点原有指向,将 curr.next 指向 prev,随后三个指针同步向前移动。遍历结束后 prev 即为新链表头节点。 时间复杂度:\(O(n)\),空间复杂度:\(O(1)\)
ListNode reverseList(ListNode head) {
ListNode prev = null, curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
递归解法
递归深入至链表末尾,回溯阶段反转节点指针:head.next.next = head,同时断开原有指针 head.next = null,防止链表循环。 时间复杂度:\(O(n)\),空间复杂度:\(O(n)\)(递归栈开销)
面试高频追问:如何反转链表的指定区间(LeetCode 92)? 先定位反转区间的起始节点,对区间内链表执行反转操作,最后重新接上断开的链表指针;需要额外处理反转起点就是头节点的边界场景。
Q2:两数之和(LeetCode 1)
题目描述:给定整型数组与目标值,在数组中找到两个元素,使其相加等于目标值,返回两个元素对应的数组下标。
暴力解法
双重循环遍历所有两两组合;时间复杂度 \(O(n^2)\),一般不作为最优解。
哈希表解法
一次遍历数组,遍历过程中计算差值 complement = target - nums[i]。 判断哈希表中是否已经存在该差值:存在则直接返回两个下标;不存在就将当前数值和下标存入哈希表。 时间复杂度:\(O(n)\),空间复杂度:\(O(n)\)
int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int comp = target - nums[i];
if (map.containsKey(comp)) {
return new int[]{map.get(comp), i};
}
map.put(nums[i], i);
}
return new int[]{};
}
面试高频追问:如果输入数组本身有序,如何优化? 采用双指针方案:左指针从头、右指针从尾部开始相向移动;两数之和小于目标则左指针右移,大于目标则右指针左移。该方案无需哈希表,空间复杂度 \(O(1)\)。
Q3:有效的括号(LeetCode 20)
题目描述:输入字符串仅包含 ()、{}、[],判断括号是否有效闭合,左括号必须以正确顺序匹配对应类型的右括号。
栈解法
遍历字符串:遇到左括号直接入栈;遇到右括号,检查栈顶元素是否为对应左括号,匹配成功则弹出栈顶元素;栈为空或者括号不匹配直接判定无效。遍历完成栈为空代表全部匹配成功。 时间复杂度:\(O(n)\),空间复杂度:\(O(n)\)
boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
Map<Character, Character> map = Map.of(')', '(', '}', '{', ']', '[');
for (char c : s.toCharArray()) {
if (map.containsKey(c)) {
if (stack.isEmpty() || !stack.peek().equals(map.get(c))) {
return false;
}
stack.pop();
} else {
stack.push(c);
}
}
return stack.isEmpty();
}
面试高频追问:最少移除多少个括号,可以让字符串变成有效括号? 一次遍历统计未匹配的左括号、右括号数量,二者相加即为最少移除次数。
Q4:无重复字符的最长子串(LeetCode 3)
题目描述:给定字符串,找出其中不含有重复字符的最长子串的长度。
滑动窗口解法
左右指针组成滑动窗口,右指针不断向右扩张窗口范围;当检测到重复字符,左指针移动至重复字符下一位。HashMap 记录字符最新出现的下标位置,全程更新最长子串长度。 时间复杂度:\(O(n)\),空间复杂度:\(O(\min(n,m))\),m 代表字符集大小
int lengthOfLongestSubstring(String s) {
Map<Character, Integer> map = new HashMap<>();
int max = 0, left = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
if (map.containsKey(c)) {
left = Math.max(left, map.get(c) + 1);
}
map.put(c, right);
max = Math.max(max, right - left + 1);
}
return max;
}
面试高频追问:滑动窗口通用解题模板是什么?
- 右指针向右扩展窗口,更新窗口内状态;
- 判断当前窗口是否满足题目约束;
- 满足条件时统计结果;不满足条件则移动左指针收缩窗口。
Q5:合并区间(LeetCode 56)
题目描述:给出若干区间数组 [start, end],合并所有存在重叠的区间,返回合并完成后的区间列表。
解题思路
第一步按照区间起始位置从小到大排序;遍历区间列表,判断当前区间是否与结果列表最后一个区间重叠:重叠则合并区间,更新区间右端最大值;不重叠直接加入结果集合。 时间复杂度:\(O(n \log n)\)(排序开销),空间复杂度:\(O(n)\)
int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
List<int[]> result = new ArrayList<>();
for (int[] interval : intervals) {
if (result.isEmpty() || result.get(result.size()-1)[1] < interval[0]) {
result.add(interval);
} else {
result.get(result.size()-1)[1] = Math.max(result.get(result.size()-1)[1], interval[1]);
}
}
return result.toArray(new int[0][]);
}
面试高频追问:插入新区间如何处理(LeetCode 57)? 方案一:新区间追加至原数组,排序后复用合并区间逻辑; 方案二:一次遍历找到插入位置,原地完成区间合并,无需二次排序。
Q6:LRU 缓存设计(LeetCode 146)
题目描述:设计一个 LRU(最近最少使用)缓存,实现 get(key) 和 put(key,value) 两个接口,两个操作时间复杂度都需要达到 \(O(1)\)。
核心设计方案
采用「HashMap + 双向链表」的数据结构。HashMap 保存 key 到链表节点的映射;双向链表维护数据访问顺序,链表头部存放最近访问过的数据,尾部存放最久未访问数据。
- get:查到节点后,将节点移动至链表头部;查无结果返回‑1;
- put:key 存在则更新数值并移到头部;不存在新建节点插入头部;缓存容量已满时删除链表尾部最久未使用节点。
面试高频追问:Java 的 LinkedHashMap 是否可以实现 LRU? 可以实现。构造函数传入
accessOrder=true,并重写removeEldestEntry即可快速实现 LRU;但是手写面试题时面试官一般要求自主实现 HashMap + 双向链表版本,不推荐直接使用 LinkedHashMap 偷懒。
Q7:二分查找及其常见变体
基础二分查找:在有序数组内查找目标值,时间复杂度 \(O(\log n)\)。
高频变体题型:
- 查找第一个大于等于 target 的下标(lower_bound)
- 查找最后一个小于等于 target 的下标
- 旋转升序数组查找最小值
- 旋转升序数组搜索目标元素
面试高频追问:什么场景适合使用二分查找? 有序数组搜索问题;答案具备单调性特征的题目,例如「最小化最大值」「最大化最小值」类题型。
Q8:美团算法面试备考指南
高频刷题清单
链表(反转链表、合并链表、环形链表)、哈希表(两数之和、字母异位词)、栈(有效括号、最小栈)、滑动窗口(最长无重复子串)、区间(合并、插入区间)、二分查找。
备考建议
- 每个题型刷 5‑10 道中等难度题目,整理出对应题型解题模板;
- 面试答题顺序:先口头讲解完整解题思路 → 再动手编写代码 → 手动带入测试用例走一遍流程校验;
高频扣分避坑清单
- 忽略空数组、空链表边界判断;
- 链表遍历忘记判空,出现空指针异常;
- 数组下标处理不当引发越界;
- 两数相加没有考虑整型溢出;
- 写完代码直接提交,没有自测验证。
小结
美团客户端算法面试重在考察基础算法的工程落地能力。刷题过程不要只追求 AC 通过,要主动思考每道题面试官可能抛出的追问,同时养成边界自测习惯,面试中才能稳稳拿下算法环节。
面试Tips:美团算法面Medium为主,链表题(反转、找环)、哈希表(两数之和)、栈(有效括号)、滑动窗口(最长子串)、区间合并是高频。代码要能跑通、边界要处理、复杂度要讲清。面试时先讲思路确认方向对再写代码,别闷头写完了发现方向错了。
下一篇进入外卖系统专项——实时定位系统、订单状态机、骑手调度算法理解、多端数据同步。
刷过LeetCode Hot 100的同学扣1,你觉得美团算法面试最难的是哪类题?
本系列连载中,关注不迷路,下一篇:美团架构师(外卖系统专项)面试真题
系列简介:Android大厂面经连载,覆盖字节跳动、腾讯、阿里、美团等40+企业,从初级到架构师全岗位覆盖。每篇文章包含真实面试题+详细答案+代码示例,帮你拿到大厂Offer。