题号 | 题目 | LeetCode | 难度 | 大厂 | 考频 |
|---|---|---|---|---|---|
1 | 两数之和 | 1 | ⭐ | 字节/阿里/腾讯 | ⭐⭐⭐⭐⭐ |
2 | 第K大 | 215 | ⭐⭐ | 字节/腾讯 | ⭐⭐⭐⭐ |
3 | 盛水容器 | 11 | ⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
4 | 移动零 | 283 | ⭐ | 微软/百度 | ⭐⭐⭐ |
5 | 颜色分类 | 75 | ⭐⭐ | 字节/腾讯 | ⭐⭐⭐ |
6 | 只出现一次 | 136 | ⭐ | 腾讯/阿里 | ⭐⭐⭐⭐ |
7 | 多数元素 | 169 | ⭐ | 字节/美团 | ⭐⭐⭐⭐ |
8 | 合并区间 | 56 | ⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
9 | 反转链表 | 206 | ⭐ | 全大厂 | ⭐⭐⭐⭐⭐ |
10 | 反转链表II | 92 | ⭐⭐ | 字节/腾讯 | ⭐⭐⭐ |
11 | 环形链表I | 141 | ⭐ | 字节/腾讯 | ⭐⭐⭐⭐⭐ |
12 | 环形链表II | 142 | ⭐⭐ | 阿里/拼多多 | ⭐⭐⭐⭐ |
13 | 合并有序链表 | 21 | ⭐ | 阿里/腾讯 | ⭐⭐⭐⭐⭐ |
14 | 两两交换 | 24 | ⭐⭐ | 字节/微软 | ⭐⭐⭐ |
15 | 删除倒数N | 19 | ⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
16 | 回文链表 | 234 | ⭐⭐ | 腾讯/美团 | ⭐⭐⭐ |
17 | 无重复子串 | 3 | ⭐⭐ | 全大厂 | ⭐⭐⭐⭐⭐ |
18 | 最长回文子串 | 5 | ⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
19 | 有效括号 | 20 | ⭐ | 字节/拼多多 | ⭐⭐⭐⭐ |
20 | 字符串相加 | 415 | ⭐ | 字节/美团 | ⭐⭐⭐ |
21 | 字符串相乘 | 43 | ⭐⭐ | 阿里/腾讯 | ⭐⭐⭐ |
22 | 翻转单词 | 151 | ⭐⭐ | 字节/微软 | ⭐⭐⭐ |
23 | 最小覆盖子串 | 76 | ⭐⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
24 | 最长公共前缀 | 14 | ⭐ | 腾讯/美团 | ⭐⭐⭐ |
25 | 层序遍历 | 102 | ⭐⭐ | 阿里/百度 | ⭐⭐⭐⭐⭐ |
26 | 最大深度 | 104 | ⭐ | 全大厂 | ⭐⭐⭐⭐⭐ |
27 | 二叉树直径 | 543 | ⭐⭐ | 字节/腾讯 | ⭐⭐⭐⭐ |
28 | 翻转二叉树 | 226 | ⭐ | 谷歌/字节 | ⭐⭐⭐⭐ |
29 | 对称二叉树 | 101 | ⭐ | 腾讯/百度 | ⭐⭐⭐⭐ |
30 | 路径总和 | 112 | ⭐ | 阿里/拼多多 | ⭐⭐⭐ |
31 | BST的LCA | 235 | ⭐⭐ | 阿里/腾讯 | ⭐⭐⭐⭐ |
32 | 验证BST | 98 | ⭐⭐ | 字节/亚马逊 | ⭐⭐⭐⭐⭐ |
33 | 爬楼梯 | 70 | ⭐ | 腾讯/阿里 | ⭐⭐⭐⭐⭐ |
34 | 最大子数组 | 53 | ⭐⭐ | 字节/美团 | ⭐⭐⭐⭐⭐ |
35 | 打家劫舍 | 198 | ⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
36 | 打家劫舍II | 213 | ⭐⭐ | 字节/腾讯 | ⭐⭐⭐ |
37 | 零钱兑换 | 322 | ⭐⭐ | 亚马逊/微软 | ⭐⭐⭐⭐ |
38 | 最长递增子序列 | 300 | ⭐⭐ | 腾讯/阿里 | ⭐⭐⭐⭐ |
39 | 最长公共子序列 | 1143 | ⭐⭐ | 阿里/腾讯 | ⭐⭐⭐⭐ |
40 | 最小路径和 | 64 | ⭐⭐ | 字节/美团 | ⭐⭐⭐ |
41 | 每日温度 | 739 | ⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
42 | 最大矩形 | 84 | ⭐⭐⭐ | 字节/腾讯 | ⭐⭐⭐ |
43 | 全排列 | 46 | ⭐⭐ | 字节/美团 | ⭐⭐⭐⭐ |
44 | 子集 | 78 | ⭐⭐ | 阿里/腾讯 | ⭐⭐⭐⭐ |
45 | 组合总和 | 39 | ⭐⭐ | 字节/百度 | ⭐⭐⭐ |
46 | 单词搜索 | 79 | ⭐⭐ | 字节/亚马逊 | ⭐⭐⭐ |
47 | 数据流中位数 | 295 | ⭐⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐ |
48 | 前K高频 | 347 | ⭐⭐ | 字节/腾讯 | ⭐⭐⭐⭐ |
49 | LRU缓存 | 146 | ⭐⭐ | 字节/阿里/腾讯 | ⭐⭐⭐⭐⭐ |
50 | 搜索旋转数组 | 33 | ⭐⭐ | 字节/阿里 | ⭐⭐⭐⭐⭐ |
使用建议
第一阶段:按LeetCode题号刷原题,夯实基础,熟悉每道题的核心解法
第二阶段:看"方案B"追问链,自己模拟面试回答,锻炼临场应变和思路拓展能力
第三阶段:找朋友按追问链模拟面试,适应面试节奏,查漏补缺
1. 两数之和
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 1. Two Sum |
难度 | ⭐ 简单 |
大厂 | 字节、阿里、腾讯、美团、百度 |
考频 | ⭐⭐⭐⭐⭐(100%必考) |
真实面经 | 字节一面、阿里二面、腾讯一面 |
【方案B · 面试追问链】
Q1(基础):写一下两数之和。
def twoSum(nums, target):d = {}for i, n in enumerate(nums):if target - n in d:return [d[target-n], i]d[n] = i
Q2(扩展):三数之和呢?
> 排序 + 双指针,O(n²)。固定第一个数,然后双指针找另外两个。
Q3(扩展):如果数组有100亿个数,内存放不下,怎么办?
> 外部排序 + 分块,或者哈希分桶,同一个桶内计算。
Q4(分布式):分布在100台机器上,每台1亿个数?
> MapReduce思想:哈希分桶,同一桶内计算。或者用分布式哈希表。
Q5(变种):如果要求返回所有不重复的三元组?
> 排序 + 跳过重复数字,固定第一个后双指针,同时跳过重复。
2. 数组中的第K个最大元素
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 215. Kth Largest Element |
难度 | ⭐⭐ 中等 |
大厂 | 字节、腾讯、亚马逊、微软 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节二面、腾讯一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
import heapqdef findKthLargest(nums, k):return heapq.nlargest(k, nums)[-1]
Q2(手写):不用堆,手写快排分区方法。
> 快速选择(Quick Select),平均O(n),最坏O(n²)。每次选pivot分区,只递归一边。
Q3(优化):如何避免最坏情况?
> 随机选择pivot / 三数取中法 / 中位数的中位数(BFPRT)。
Q4(海量数据):如果数据量100亿,内存放不下?
> 使用最小堆,维护K个最大元素,一次遍历,O(n log K)。
3. 盛最多水的容器
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 11. Container With Most Water |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、腾讯 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节一面、阿里一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def maxArea(height):l, r = 0, len(height)-1res = 0while l < r:res = max(res, min(height[l], height[r]) * (r-l))if height[l] < height[r]: l += 1else: r -= 1return res
Q2(原理):为什么移动短边?
> 移动短边可能找到更高的边,增加面积;移动长边只会让宽度减小,高度不会超过短边,面积只会变小。
Q3(变种):如果有负数高度?
> 容器高度不能为负,可以先过滤或直接返回0。
Q4(二维):如果是二维矩阵,找最大矩形水池?
> 按行枚举,每行看作一个直方图,用单调栈求最大矩形。
4. 移动零
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 283. Move Zeroes |
难度 | ⭐ 简单 |
大厂 | 微软、亚马逊、百度 |
考频 | ⭐⭐⭐ |
真实面经 | 百度一面、微软一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def moveZeroes(nums):idx = 0for n in nums:if n != 0:nums[idx] = nidx += 1nums[idx:] = [0] * (len(nums)-idx)
Q2(要求):能否保持非零元素的相对顺序?
> 当前方法保持了相对顺序。
Q3(要求):能否O(1)空间?
> 当前方法O(1)空间。
Q4(要求):能否一次遍历且不额外用数组?
> 双指针交换法:遇到非零就与左指针交换,左指针++。
5. 颜色分类(荷兰国旗)
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 75. Sort Colors |
难度 | ⭐⭐ 中等 |
大厂 | 字节、腾讯、拼多多 |
考频 | ⭐⭐⭐ |
真实面经 | 字节二面、拼多多一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def sortColors(nums):l, mid, r = 0, 0, len(nums)-1while mid <= r:if nums[mid] == 0:nums[l], nums[mid] = nums[mid], nums[l]l += 1; mid += 1elif nums[mid] == 2:nums[mid], nums[r] = nums[r], nums[mid]r -= 1else:mid += 1
Q2(原理):为什么遇到0要移动l和mid,遇到2只移动r?
> 0换过来的一定是0或1(已扫描过),所以mid可以前进;2换过来的未扫描过,需要重新检查。
Q3(变种):如果是4种颜色(0,1,2,3)?
> 双指针法不再适用,用计数排序(O(n)时间,O(k)空间)或桶排序。
Q4(要求):要求O(n)时间,O(1)空间。
> 当前方法满足。
6. 只出现一次的数字
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 136. Single Number |
难度 | ⭐ 简单 |
大厂 | 阿里、腾讯、小米 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 腾讯一面、阿里一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def singleNumber(nums):res = 0for n in nums:res ^= nreturn res
Q2(原理):为什么异或能行?
> a^a=0,0^a=a,异或满足交换律结合律。
Q3(变种):如果其他数字都出现3次,只有1个出现1次?
> 用位运算:统计每一位上1的个数 mod 3。
Q4(变种):如果有两个数字只出现1次,其他出现2次?
> 异或得到x^y,找到某一位为1,分组异或。
7. 多数元素
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 169. Majority Element |
难度 | ⭐ 简单 |
大厂 | 字节、美团、百度 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 美团一面、字节一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def majorityElement(nums):cnt, res = 0, 0for n in nums:if cnt == 0:res = ncnt += 1 if n == res else -1return res
Q2(原理):摩尔投票法为什么正确?
> 多数元素出现的次数比其他所有元素出现次数之和还要多,正负抵消后剩下的就是多数元素。
Q3(其他解法):还有其他解法吗?
> 哈希表O(n)空间;排序后取中间O(n log n);分治法。
Q4(变种):找出现次数超过 n/3 的元素?
> 最多有两个,用两个候选人的摩尔投票。
8. 合并区间
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 56. Merge Intervals |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、滴滴 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节一面、滴滴一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def merge(intervals):intervals.sort()res = [intervals[0]]for s, e in intervals[1:]:if s <= res[-1][1]:res[-1][1] = max(res[-1][1], e)else:res.append([s, e])return res
Q2(变种):插入一个新区间并合并。
> 二分找到插入位置,然后类似合并。
Q3(变种):找两个区间列表的交集。
> 双指针,每次取重叠部分。
Q4(大数据):区间长度总和10^9,区间个数10^6?
> 排序 + 扫描,O(n log n) 可以接受。可以进一步用扫描线。
二、链表(9-16)
9. 反转链表
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 206. Reverse Linked List |
难度 | ⭐ 简单 |
大厂 | 所有大厂必考 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 字节/阿里/腾讯/美团 一面 |
【方案B · 面试追问链】
Q1(基础):写一下(迭代)。
def reverseList(head):pre, cur = None, headwhile cur:nxt = cur.nextcur.next = prepre, cur = cur, nxtreturn pre
Q2(要求):递归写法。
def reverseList(head):if not head or not head.next:return headnew_head = reverseList(head.next)head.next.next = headhead.next = Nonereturn new_head
Q3(扩展):反转链表 II(区间反转)。
> 找到pre节点,局部反转。
Q4(扩展):K个一组反转链表。
> 先判断是否有K个节点,然后反转K个,递归或迭代。
10. 反转链表 II(区间反转)
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 92. Reverse Linked List II |
难度 | ⭐⭐ 中等 |
大厂 | 字节、腾讯、美团 |
考频 | ⭐⭐⭐ |
真实面经 | 字节二面、腾讯一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def reverseBetween(head, left, right):dummy = ListNode(next=head)pre = dummyfor _ in range(left-1):pre = pre.nextcur = pre.nextfor _ in range(right-left):nxt = cur.nextcur.next = nxt.nextnxt.next = pre.nextpre.next = nxtreturn dummy.next
Q2(原理):为什么用头插法?
> 头插法可以原地反转,不需要额外空间。
Q3(边界):如果left=1?
> dummy节点处理,无需特殊判断。
Q4(要求):如果用递归实现?
> 比较复杂,一般用迭代。
11. 环形链表 I
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 141. Linked List Cycle |
难度 | ⭐ 简单 |
大厂 | 字节、腾讯、微软 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 字节一面、腾讯一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def hasCycle(head):slow = fast = headwhile fast and fast.next:slow = slow.nextfast = fast.next.nextif slow == fast:return Truereturn False
Q2(原理):为什么快慢指针一定会相遇?
> 快指针比慢指针快1步,相当于追及问题,环内一定能追上。
Q3(空间):空间复杂度?
> O(1)。
Q4(变种):如何找到入环点?
> 相遇后,一个从头开始,一个从相遇点,同速走,再次相遇点即入环点。
12. 环形链表 II(找入环点)
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 142. Linked List Cycle II |
难度 | ⭐⭐ 中等 |
大厂 | 阿里、拼多多、亚马逊 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 阿里二面、拼多多一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def detectCycle(head):slow = fast = headwhile fast and fast.next:slow = slow.nextfast = fast.next.nextif slow == fast:p = headwhile p != slow:p = p.nextslow = slow.nextreturn preturn None
Q2(推导):为什么从头和相遇点同速走就能找到入环点?
> 设入环前长度a,环长度b,相遇时slow走a+b,fast走a+b+kb,fast是slow两倍,可得a = (k-1)b + (b - x),所以从头走a步和从相遇点走b-x步会重合。
Q3(要求):空间复杂度?
> O(1)。
Q4(变种):如果要求返回环的长度?
> 相遇后继续走,再次相遇时走的步数即环长。
13. 合并两个有序链表
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 21. Merge Two Sorted Lists |
难度 | ⭐ 简单 |
大厂 | 阿里、腾讯、快手 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 阿里一面、腾讯一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def mergeTwoLists(l1, l2):dummy = cur = ListNode()while l1 and l2:if l1.val < l2.val:cur.next = l1l1 = l1.nextelse:cur.next = l2l2 = l2.nextcur = cur.nextcur.next = l1 or l2return dummy.next
Q2(要求):递归写法。
def mergeTwoLists(l1, l2):if not l1: return l2if not l2: return l1if l1.val < l2.val:l1.next = mergeTwoLists(l1.next, l2)return l1else:l2.next = mergeTwoLists(l1, l2.next)return l2
Q3(扩展):合并K个有序链表。
> 分治法(两两合并)或使用最小堆。
Q4(复杂度):时间复杂度?
> O(m+n)。
14. 两两交换链表节点
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 24. Swap Nodes in Pairs |
难度 | ⭐⭐ 中等 |
大厂 | 字节、微软 |
考频 | ⭐⭐⭐ |
真实面经 | 字节一面、微软一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def swapPairs(head):dummy = ListNode(next=head)pre = dummywhile pre.next and pre.next.next:a = pre.nextb = a.nextpre.next, b.next, a.next = b, a, b.nextpre = areturn dummy.next
Q2(要求):递归写法。
def swapPairs(head):if not head or not head.next:return headnew_head = head.nexthead.next = swapPairs(new_head.next)new_head.next = headreturn new_head
Q3(变种):K个一组反转链表。
> 更复杂,需要判断是否有K个节点。
Q4(要求):空间复杂度?
> 迭代O(1),递归O(n)栈空间。
15. 删除链表倒数第N个节点
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 19. Remove Nth Node From End |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、百度 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节一面、阿里一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def removeNthFromEnd(head, n):dummy = ListNode(next=head)fast = slow = dummyfor _ in range(n+1):fast = fast.nextwhile fast:slow = slow.nextfast = fast.nextslow.next = slow.next.nextreturn dummy.next
Q2(原理):为什么快指针先走n+1步?
> 让slow指向要删除节点的前一个节点。
Q3(边界):如果删除的是头节点?
> dummy节点处理,返回dummy.next即可。
Q4(要求):如果只能遍历一次?
> 当前方法就是一次遍历。
16. 回文链表
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 234. Palindrome Linked List |
难度 | ⭐⭐ 中等 |
大厂 | 腾讯、美团、小米 |
考频 | ⭐⭐⭐ |
真实面经 | 腾讯一面、美团一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def isPalindrome(head):slow = fast = headpre = Nonewhile fast and fast.next:fast = fast.next.nextnxt = slow.nextslow.next = prepre = slowslow = nxtif fast:slow = slow.nextwhile pre and pre.val == slow.val:pre = pre.nextslow = slow.nextreturn not pre
Q2(原理):这个代码做了什么事?
> 快慢指针找中点,前半部分反转,然后比较。
Q3(空间):空间复杂度?
> O(1)。
Q4(要求):如果用数组辅助?
> 更简单但O(n)空间,面试可能不满意。
三、字符串(17-24)
17. 无重复字符的最长子串
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 3. Longest Substring Without Repeating |
难度 | ⭐⭐ 中等 |
大厂 | 所有大厂Top1高频 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 |
【方案B · 面试追问链】
Q1(基础):写一下。
def lengthOfLongestSubstring(s):d = {}left = res = 0for right, c in enumerate(s):if c in d and d[c] >= left:left = d[c] + 1d[c] = rightres = max(res, right-left+1)return res
Q2(原理):为什么左指针要跳到重复字符的下一位?
> 保证窗口内无重复。
Q3(变种):如果允许最多K个重复字符?
> 滑动窗口 + 计数,当超过K时移动左指针。
Q4(变种):如果字符串长度10^6?
> O(n)可以过。
18. 最长回文子串
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 5. Longest Palindromic Substring |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、腾讯 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节二面、阿里二面 |
【方案B · 面试追问链】
Q1(基础):写一下(中心扩展)。
def longestPalindrome(s):def expand(l, r):while l >= 0 and r < len(s) and s[l] == s[r]:l -= 1r += 1return s[l+1:r]res = ''for i in range(len(s)):res = max(res, expand(i,i), expand(i,i+1), key=len)return res
Q2(复杂度):时间复杂度?
> O(n²),空间O(1)。
Q3(优化):能否O(n)?
> Manacher算法,但面试一般不要求写。
Q4(变种):最长回文子序列。
> DP,不是连续子串。
19. 有效的括号
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 20. Valid Parentheses |
难度 | ⭐ 简单 |
大厂 | 字节、拼多多、百度 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节一面、拼多多一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def isValid(s):stack = []d = {')':'(', ']':'[', '}':'{'}for c in s:if c not in d:stack.append(c)else:if not stack or stack.pop() != d[c]:return Falsereturn not stack
Q2(变种):如果括号有优先级(如{ [ ( ) ] } 嵌套必须按顺序)?
> 需要额外检查栈顶优先级。
Q3(变种):如果字符串很长(10^7)?
> O(n)可以过,栈最大深度n。
Q4(变种):返回最长有效括号子串长度?
> 用栈存下标,LeetCode 32。
20. 字符串相加
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 415. Add Strings |
难度 | ⭐ 简单 |
大厂 | 字节、美团、快手 |
考频 | ⭐⭐⭐ |
真实面经 | 字节一面、快手一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def addStrings(num1, num2):i, j, carry = len(num1)-1, len(num2)-1, 0res = []while i >= 0 or j >= 0 or carry:a = int(num1[i]) if i >= 0 else 0b = int(num2[j]) if j >= 0 else 0carry, t = divmod(a + b + carry, 10)res.append(str(t))i -= 1; j -= 1return ''.join(res[::-1])
Q2(变种):字符串相乘。
> LeetCode 43,用数组存每位结果。
Q3(变种):二进制相加。
> 类似,进位改为2。
Q4(大数):如果数字长度10^6?
> 可以,O(n)。
21. 字符串相乘
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 43. Multiply Strings |
难度 | ⭐⭐ 中等 |
大厂 | 阿里、腾讯、华为 |
考频 | ⭐⭐⭐ |
真实面经 | 阿里二面、腾讯二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def multiply(num1, num2):if num1 == "0" or num2 == "0": return "0"m, n = len(num1), len(num2)res = [0] * (m + n)for i in range(m-1, -1, -1):a = int(num1[i])for j in range(n-1, -1, -1):b = int(num2[j])res[i+j+1] += a * bres[i+j] += res[i+j+1] // 10res[i+j+1] %= 10idx = 0while res[idx] == 0: idx += 1return ''.join(map(str, res[idx:]))
Q2(原理):为什么数组长度是m+n?
> 两数相乘,结果最多m+n位。
Q3(优化):时间复杂度?
> O(m*n)。
Q4(变种):如果用快速傅里叶变换(FFT)?
> O(n log n),但面试不要求。
22. 翻转字符串里的单词
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 151. Reverse Words in a String |
难度 | ⭐⭐ 中等 |
大厂 | 字节、微软、百度 |
考频 | ⭐⭐⭐ |
真实面经 | 字节一面、微软一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def reverseWords(s):return ' '.join(s.split()[::-1])
Q2(要求):不使用split。
> 遍历字符串,提取单词到列表,然后逆序拼接。
Q3(要求):O(1)额外空间。
> 先反转整个字符串,再反转每个单词,同时处理多余空格。
Q4(变种):反转字符串里的单词顺序,但保持单词内字符顺序不变。
> 就是本题。
23. 最小覆盖子串
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 76. Minimum Window Substring |
难度 | ⭐⭐⭐ 困难 |
大厂 | 字节、阿里、腾讯 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节三面、阿里二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def minWindow(s, t):from collections import Counterneed = Counter(t)window = {}left = valid = 0start, min_len = 0, float('inf')for right, c in enumerate(s):if c in need:window[c] = window.get(c, 0) + 1if window[c] == need[c]:valid += 1while valid == len(need):if right - left + 1 < min_len:start, min_len = left, right - left + 1d = s[left]if d in need:if window[d] == need[d]:valid -= 1window[d] -= 1left += 1return s[start:start+min_len] if min_len != float('inf') else ''
Q2(复杂度):时间复杂度?
> O(m+n),每个字符最多进窗口一次、出窗口一次。
Q3(变种):如果t有重复字符?
> 当前解法已处理,need计数匹配。
Q4(变种):找所有异位词的子串?
> LeetCode 438,类似滑动窗口。
24. 最长公共前缀
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 14. Longest Common Prefix |
难度 | ⭐ 简单 |
大厂 | 腾讯、美团、小米 |
考频 | ⭐⭐⭐ |
真实面经 | 腾讯一面、美团一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def longestCommonPrefix(strs):if not strs: return ''pre = strs[0]for s in strs[1:]:while not s.startswith(pre):pre = pre[:-1]if not pre: return ''return pre
Q2(复杂度):时间复杂度?
> O(S),S为所有字符串长度和。
Q3(优化):如何优化?
> 横向扫描、纵向扫描、分治法、二分查找。
Q4(变种):如果字符串数组很大?
> 纵向扫描可以提前终止。
四、二叉树 & BFS/DFS(25-32)
25. 二叉树的层序遍历
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 102. Binary Tree Level Order |
难度 | ⭐⭐ 中等 |
大厂 | 阿里、百度、京东 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 阿里一面、百度一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def levelOrder(root):if not root: return []q = deque([root])res = []while q:level = []for _ in range(len(q)):node = q.popleft()level.append(node.val)if node.left: q.append(node.left)if node.right: q.append(node.right)res.append(level)return res
Q2(变种):锯齿形层序遍历。
> 偶数层反转或用双端队列。
Q3(变种):二叉树的右视图。
> 每层最后一个节点。
Q4(变种):二叉树的最大宽度。
> BFS时记录节点编号。
26. 二叉树的最大深度
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 104. Maximum Depth of Binary Tree |
难度 | ⭐ 简单 |
大厂 | 所有大厂基础题 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 字节/阿里/腾讯 一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def maxDepth(root):if not root: return 0return max(maxDepth(root.left), maxDepth(root.right)) + 1
Q2(要求):迭代写法。
> BFS层序遍历,每层深度+1。
Q3(变种):最小深度。
> 叶子节点时返回深度,注意单支情况。
Q4(变种):N叉树的最大深度。
> 遍历所有子节点取max。
27. 二叉树的直径
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 543. Diameter of Binary Tree |
难度 | ⭐⭐ 中等 |
大厂 | 字节、腾讯、美团 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节二面、腾讯二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def diameterOfBinaryTree(root):res = 0def dfs(node):nonlocal resif not node: return 0l = dfs(node.left)r = dfs(node.right)res = max(res, l + r)return max(l, r) + 1dfs(root)return res
Q2(原理):为什么是左高度+右高度?
> 直径是经过该节点的最长路径 = 左子树深度 + 右子树深度。
Q3(变种):如果求的是节点数而不是边数?
> 返回l+r+1。
Q4(变种):二叉树的最大路径和。
> LeetCode 124,DP类似。
28. 翻转二叉树
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 226. Invert Binary Tree |
难度 | ⭐ 简单 |
大厂 | 谷歌、字节、阿里 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节一面、谷歌一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def invertTree(root):if not root: return Noneroot.left, root.right = invertTree(root.right), invertTree(root.left)return root
Q2(要求):迭代写法。
> BFS或DFS栈。
Q3(变种):对称二叉树。
> 递归判断左右镜像。
Q4(幽默):知道这个题为什么火吗?
> Homebrew作者面试Google没写出来。
29. 对称二叉树
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 101. Symmetric Tree |
难度 | ⭐ 简单 |
大厂 | 腾讯、百度、小米 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 腾讯一面、百度一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def isSymmetric(root):def dfs(l, r):if not l and not r: return Trueif not l or not r: return Falsereturn l.val == r.val and dfs(l.left, r.right) and dfs(l.right, r.left)return dfs(root, root)
Q2(要求):迭代写法。
> 队列成对入队出队。
Q3(变种):相同的树。
> LeetCode 100,更简单。
Q4(变种):另一棵树的子树。
> LeetCode 572。
30. 路径总和
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 112. Path Sum |
难度 | ⭐ 简单 |
大厂 | 阿里、拼多多、网易 |
考频 | ⭐⭐⭐ |
真实面经 | 阿里一面、拼多多一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def hasPathSum(root, targetSum):if not root: return Falseif not root.left and not root.right:return root.val == targetSumreturn hasPathSum(root.left, targetSum-root.val) or hasPathSum(root.right, targetSum-root.val)
Q2(变种):返回所有路径。
> LeetCode 113,带path回溯。
Q3(变种):路径总和 III(任意起点终点)。
> LeetCode 437,前缀和+哈希。
Q4(变种):二叉树中的最大路径和。
> LeetCode 124,困难题。
31. 二叉搜索树的最近公共祖先
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 235. Lowest Common Ancestor of BST |
难度 | ⭐⭐ 中等 |
大厂 | 阿里、腾讯、字节 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 阿里一面、腾讯一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def lowestCommonAncestor(root, p, q):if root.val > p.val and root.val > q.val:return lowestCommonAncestor(root.left, p, q)if root.val < p.val and root.val < q.val:return lowestCommonAncestor(root.right, p, q)return root
Q2(变种):普通二叉树的LCA。
> 递归:左子树有无p/q,右子树有无p/q。
Q3(变种):如果节点不一定存在?
> 先遍历检查是否存在,或返回标志位。
Q4(变种):LCA with parent指针。
> 用哈希表或双指针。
32. 验证二叉搜索树
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 98. Validate Binary Search Tree |
难度 | ⭐⭐ 中等 |
大厂 | 字节、亚马逊、微软 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 字节二面、亚马逊一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def isValidBST(root):def dfs(node, l, r):if not node: return Trueif not (l < node.val < r): return Falsereturn dfs(node.left, l, node.val) and dfs(node.right, node.val, r)return dfs(root, float('-inf'), float('inf'))
Q2(变种):中序遍历法。
> 中序遍历,检查是否严格递增。
Q3(变种):BST找第K小的元素。
> 中序遍历到第K个。
Q4(变种):BST找前驱和后继。
> 左子树最右 / 右子树最左。
五、动态规划 DP(33-40)
33. 爬楼梯
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 70. Climbing Stairs |
难度 | ⭐ 简单 |
大厂 | 腾讯、阿里、小米 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 腾讯一面、阿里一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def climbStairs(n):a, b = 1, 1for _ in range(n-1):a, b = b, a+breturn b
Q2(变种):最小花费爬楼梯。
> dp[i] = min(dp[i-1], dp[i-2]) + cost[i]。
Q3(变种):一次可以爬1、2、3步。
> dp[i] = dp[i-1]+dp[i-2]+dp[i-3]。
Q4(变种):有障碍物。
> dp[i] = 0 if 有障碍。
34. 最大子数组和
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 53. Maximum Subarray |
难度 | ⭐⭐ 中等 |
大厂 | 字节、美团、华为 |
【方案B · 面试追问链】
Q1(基础):写一下。
def maxSubArray(nums):res = cur = nums[0]for n in nums[1:]:cur = max(n, cur+n)res = max(res, cur)return res
Q2(变种):返回子数组的起止位置。
记录cur重置时的索引。
Q3(变种):环形数组的最大子数组和。
两种情况:不成环 / 成环(总和-最小子数组)。
Q4(变种):二维矩阵的最大子矩阵和。
枚举行边界,降维成一维。
35. 打家劫舍
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 198. House Robber |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、拼多多 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节一面、阿里一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def rob(nums):a, b = 0, 0for n in nums:a, b = b, max(b, a+n)return b
Q2(变种):打家劫舍 II(环形)。
拆成两个:不抢首、不抢尾,取max。
Q3(变种):打家劫舍 III(二叉树)。
树形DP,返回[抢当前, 不抢当前]。
Q4(变种):如果房屋是环形且相邻不能抢,但第一个和最后一个也不能同时抢。
就是打家劫舍II。
36. 打家劫舍 II(环形)
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 213. House Robber II |
难度 | ⭐⭐ 中等 |
大厂 | 字节、腾讯 |
考频 | ⭐⭐⭐ |
真实面经 | 字节二面、腾讯二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def rob(nums):def helper(l, r):a = b = 0for i in range(l, r):a, b = b, max(b, a+nums[i])return bn = len(nums)if n == 1: return nums[0]return max(helper(0, n-1), helper(1, n))
Q2(原理):为什么要拆成两个?
环形意味着首尾不能同时选,所以分别排除首和尾。
Q3(变种):如果房屋排列成二叉树?
树形DP。
Q4(变种):如果抢了第一个不能抢最后一个,但抢了最后一个可以抢第一个?
不对称条件,需要特殊处理。
37. 零钱兑换
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 322. Coin Change |
难度 | ⭐⭐ 中等 |
大厂 | 亚马逊、微软、字节 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 亚马逊一面、字节二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def coinChange(coins, amount):dp = [float('inf')] * (amount+1)dp[0] = 0for c in coins:for i in range(c, amount+1):dp[i] = min(dp[i], dp[i-c] + 1)return dp[amount] if dp[amount] != float('inf') else -1
Q2(变种):求组合数(凑成amount的方法数)。
dp[i] += dp[i-c],LeetCode 518。
Q3(变种):如果硬币数量有限?
多重背包问题。
Q4(变种):如果amount很大(10^6),coins很少?
BFS比DP更优。
38. 最长递增子序列
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 300. Longest Increasing Subsequence |
难度 | ⭐⭐ 中等 |
大厂 | 腾讯、阿里、字节 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 腾讯二面、阿里二面 |
【方案B · 面试追问链】
Q1(基础):写一下(贪心+二分)。
def lengthOfLIS(nums):tails = []for n in nums:if not tails or n > tails[-1]:tails.append(n)else:import bisecttails[bisect.bisect_left(tails, n)] = nreturn len(tails)
Q2(原理):tails数组的含义?
tails[i] 表示长度为 i+1 的递增子序列的最小结尾元素。
Q3(变种):最长连续递增子序列。
更简单,一次遍历。
Q4(变种):最长递增子序列的个数。
需要同时记录个数。
39. 最长公共子序列
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 1143. Longest Common Subsequence |
难度 | ⭐⭐ 中等 |
大厂 | 阿里、腾讯、华为 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 阿里二面、腾讯二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def longestCommonSubsequence(text1, text2):m, n = len(text1), len(text2)dp = [[0]*(n+1) for _ in range(m+1)]for i in range(1, m+1):for j in range(1, n+1):if text1[i-1] == text2[j-1]:dp[i][j] = dp[i-1][j-1] + 1else:dp[i][j] = max(dp[i-1][j], dp[i][j-1])return dp[m][n]
Q2(变种):最长公共子串。
要求连续,不同递推式,且需要记录最大值。
Q3(优化):空间优化。
用两行滚动数组。
Q4(变种):最短公共超序列。
返回最短字符串包含两者。
40. 最小路径和
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 64. Minimum Path Sum |
难度 | ⭐⭐ 中等 |
大厂 | 字节、美团、百度 |
考频 | ⭐⭐⭐ |
真实面经 | 字节一面、美团一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def minPathSum(grid):m, n = len(grid), len(grid[0])for i in range(m):for j in range(n):if i == 0 and j == 0: continueelif i == 0: grid[i][j] += grid[i][j-1]elif j == 0: grid[i][j] += grid[i-1][j]else: grid[i][j] += min(grid[i-1][j], grid[i][j-1])return grid[-1][-1]
Q2(变种):带障碍物的最小路径和。
有障碍物则路径数=0,LeetCode 63。
Q3(变种):输出路径。
从终点反向回溯。
Q4(变种):空间优化为O(n)。
用一维数组滚动。
六、栈、堆、回溯、设计(41-50)
41. 每日温度
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 739. Daily Temperatures |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、亚马逊 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节二面、阿里二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def dailyTemperatures(T):res, stack = [0]*len(T), []for i, t in enumerate(T):while stack and T[stack[-1]] < t:idx = stack.pop()res[idx] = i - idxstack.append(i)return res
Q2(变种):下一个更大元素 I。
LeetCode 496,更简单。
Q3(变种):下一个更大元素 II(环形)。
遍历两遍数组。
Q4(变种):接雨水。
单调栈或双指针。
42. 柱状图中最大矩形
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 84. Largest Rectangle in Histogram |
难度 | ⭐⭐⭐ 困难 |
大厂 | 字节、腾讯、华为 |
考频 | ⭐⭐⭐ |
真实面经 | 字节三面、腾讯三面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def largestRectangleArea(heights):stack, heights = [-1], heights + [0]res = 0for i, h in enumerate(heights):while heights[stack[-1]] > h:height = heights[stack.pop()]width = i - stack[-1] - 1res = max(res, height * width)stack.append(i)return res
Q2(原理):为什么最后加0?
保证最后所有元素出栈。
Q3(变种):最大矩形(二维矩阵)。
每一行当作柱状图,调用本题。
Q4(变种):直方图的水量(接雨水)。
不同逻辑。
43. 全排列
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 46. Permutations |
难度 | ⭐⭐ 中等 |
大厂 | 字节、美团、网易 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节二面、美团二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def permute(nums):res = []def back(path, rest):if not rest:res.append(path)returnfor i in range(len(rest)):back(path+[rest[i]], rest[:i]+rest[i+1:])back([], nums)return res
Q2(变种):全排列 II(有重复数字)。
排序 + visited数组去重。
Q3(变种):下一个排列。
找升序对,交换,反转。
Q4(变种):排列序列(第K个排列)。
数学方法,LeetCode 60。
44. 子集
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 78. Subsets |
难度 | ⭐⭐ 中等 |
大厂 | 阿里、腾讯、拼多多 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 阿里二面、腾讯二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def subsets(nums):res = []def dfs(path, start):res.append(path)for i in range(start, len(nums)):dfs(path+[nums[i]], i+1)dfs([], 0)return res
Q2(变种):子集 II(有重复数字)。
排序 + 跳过重复。
Q3(变种):组合。
固定长度,LeetCode 77。
Q4(变种):二进制枚举。
非回溯,用位运算。
45. 组合总和
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 39. Combination Sum |
难度 | ⭐⭐ 中等 |
大厂 | 字节、百度、微软 |
考频 | ⭐⭐⭐ |
真实面经 | 字节二面、百度二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def combinationSum(candidates, target):res = []def dfs(path, start, remain):if remain == 0:res.append(path)returnfor i in range(start, len(candidates)):if candidates[i] > remain: continuedfs(path+[candidates[i]], i, remain-candidates[i])dfs([], 0, target)return res
Q2(变种):组合总和 II(每个数只能用一次)。
排序 + 跳过重复。
Q3(变种):组合总和 III(固定个数)。
LeetCode 216。
Q4(变种):电话号码的字母组合。
LeetCode 17。
46. 单词搜索
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 79. Word Search |
难度 | ⭐⭐ 中等 |
大厂 | 字节、亚马逊、阿里 |
考频 | ⭐⭐⭐ |
真实面经 | 字节二面、亚马逊一面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def exist(board, word):m, n = len(board), len(board[0])dirs = [(-1,0),(1,0),(0,-1),(0,1)]def dfs(i, j, k):if not (0<=i<m and 0<=j<n) or board[i][j] != word[k]:return Falseif k == len(word)-1:return Truetmp, board[i][j] = board[i][j], '#'for dx, dy in dirs:if dfs(i+dx, j+dy, k+1):return Trueboard[i][j] = tmpreturn Falsefor i in range(m):for j in range(n):if dfs(i, j, 0):return Truereturn False
Q2(变种):单词搜索 II(多个单词)。
用Trie树优化,LeetCode 212。
Q3(优化):如何避免重复搜索?
用visited数组或原地修改。
Q4(变种):返回所有路径坐标。
回溯时记录路径。
47. 数据流的中位数
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 295. Find Median from Data Stream |
难度 | ⭐⭐⭐ 困难 |
大厂 | 字节、阿里、腾讯 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节三面、阿里三面 |
【方案B · 面试追问链】
Q1(基础):写一下。
class MedianFinder:def __init__(self):import heapqself.small = []self.large = []def addNum(self, num):heapq.heappush(self.small, -num)heapq.heappush(self.large, -heapq.heappop(self.small))if len(self.large) > len(self.small) + 1:heapq.heappush(self.small, -heapq.heappop(self.large))def findMedian(self):if len(self.large) > len(self.small):return self.large[0]return (self.large[0] - self.small[0]) / 2
Q2(原理):为什么用两个堆?
大顶堆放较小的一半,小顶堆放较大的一半。
Q3(变种):滑动窗口中位数。
需要懒删除,LeetCode 480。
Q4(变种):如果数据量很大,内存放不下?
分桶统计(近似中位数)。
48. 前K个高频元素
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 347. Top K Frequent Elements |
难度 | ⭐⭐ 中等 |
大厂 | 字节、腾讯、美团 |
考频 | ⭐⭐⭐⭐ |
真实面经 | 字节二面、美团二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def topKFrequent(nums, k):from collections import Counterimport heapqcnt = Counter(nums)return heapq.nlargest(k, cnt.keys(), key=cnt.get)
Q2(手写):不用heapq,手写堆。
维护一个大小为k的最小堆。
Q3(变种):频率按值排序。
相同频率按数字大小排序。
Q4(变种):用桶排序(O(n))。
频率作为桶下标,逆序遍历。
49. LRU缓存
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 146. LRU Cache |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、腾讯、微软 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 字节二面、阿里二面、腾讯二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
from collections import OrderedDictclass LRUCache:def __init__(self, capacity):self.cap = capacityself.d = OrderedDict()def get(self, key):if key not in self.d: return -1self.d.move_to_end(key)return self.d[key]def put(self, key, value):if key in self.d:self.d.move_to_end(key)self.d[key] = valueif len(self.d) > self.cap:self.d.popitem(last=False)
Q2(要求):手写双向链表 + 哈希。
面试官可能要求不用OrderedDict。
Q3(变种):LFU缓存。
LeetCode 460,更复杂,需要多级链表。
Q4(变种):LRU的多线程安全版本。
加锁或使用并发数据结构。
50. 搜索旋转排序数组
【方案A · 真题溯源】
字段 | 内容 |
|---|---|
LeetCode | 33. Search in Rotated Sorted Array |
难度 | ⭐⭐ 中等 |
大厂 | 字节、阿里、亚马逊 |
考频 | ⭐⭐⭐⭐⭐ |
真实面经 | 字节二面、阿里二面 |
【方案B · 面试追问链】
Q1(基础):写一下。
def search(nums, target):l, r = 0, len(nums)-1while l <= r:mid = (l+r)//2if nums[mid] == target:return midif nums[l] <= nums[mid]:if nums[l] <= target < nums[mid]:r = mid - 1else:l = mid + 1else:if nums[mid] < target <= nums[r]:l = mid + 1else:r = mid - 1return -1
LeetCode高频面试题速查表及使用建议
旋转数组相关变种题(补充)
Q2(变种):有重复元素(LeetCode 81)。
当nums[l]==nums[mid]时,l++。
Q3(变种):找旋转数组中的最小值(LeetCode 153)。
二分找分界点。
Q4(变种):找旋转数组中的最小值 II(有重复)