LLM 算法岗 | 字节面试常问的 leetcode 算法题汇总,附 leetcode 链接
根据小红书和牛客网的面经总结。【⭐】代表博主推测的高频题,【🎯】代表已知有身边人被问到的题,🎈 代表思路速记。
1 DP:
私心加一个背包问题,本站博客讲解(python3)
- 最长递增子序列 (LIS, LeetCode 300)【⭐】
- 题目:300. 最长递增子序列,🎈 dp 很容易就写出来了,但是 o(nlogn) 的贪心 + 二分有点复杂的,暂时没看懂,(感觉我也很难从头想到… 果然还是得多刷题
- 编辑距离【⭐】
- 题目:72. 编辑距离,本站题解博客(python3),🎈 dp[i][j] 表示 str1[0: i] 和 str2[0: j] 的编辑距离。
- Word Break (变种)【⭐】
- 题目:139. 单词拆分,本站题解博客(python3),🎈 dp[i] 表示字符串 s 的前 i 个字符(即 s[:i])是否可以被成功拆分,判断 dp[i] 是否为 1,需要遍历词表,看 str[i-word_len: i] 是否 == word。
- 注:变种通常指 II (140) 140. 单词拆分 II,本站题解博客(python3),🎈 直接把 dp[i] 定义为子串 s[i:] 能构成的所有句子列表。
- 最长公共子串【⭐】
- 题目:1143. 最长公共子序列,本站题解博客(python3),🎈 dp[i][j] 表示以 nums1 的第 i-1 个元素和 nums2 的第 j-1 个元素为结尾的公共子串的长度,考察 nums1[i-1] == nums2[j-1],dp[i-1][j],dp[i][j-1]。
- 注:LeetCode 中没有直接名为“最长公共子串”的题目。通常指 1143(子序列)。如果是严格的“子串”(连续),对应题目为 718. 最长重复子数组,本站题解博客(python3),🎈 dp[i][j] 表示以 nums1 的第 i-1 个元素和 nums2 的第 j-1 个元素为结尾的公共子数组的长度,仅考察 nums1[i-1] == nums2[j-1]。
- 2D 接雨水,接雨水 (LeetCode 42)【⭐】
- 1D 题目:42. 接雨水,本站题解博客(python3),🎈 维护双指针 left_max 和 right_max,分别表示当前位置左边和右边已遇到的最大高度,left_max = max(left_max, height[left]),right 同理。如果 left_max < right_max:说明左边是短板,left 位置的水位由 left_max 决定,water += left_max - height[left],left 指针右移。如果 left_max >= right_max,反之同理。
- 2D 题目:407. 接雨水 II,本站题解博客(python3),🎈 【①】将矩阵最外圈的所有单元格放入一个最小堆(Priority Queue)中,堆中存储 (高度,行坐标,列坐标),同时将这些单元格标记为 visited(已访问)。【②】从堆中弹出高度最小的单元格 (h, r, c)。这个 h 代表了当前包围内部区域的“最低围墙高度”,也就是木板的短板。【③】检查该单元格的上下左右四个邻居,如果邻居未访问过,且 neighbor_h < h,则邻居可以积水,water += h - neighbor_h,同时邻居以高度 h 进最小堆,因为这个位置被水填满后,其有效高度变成了 h。如果邻居的高度 neighbor_h >= h,说明这里不能积水,邻居以 neighbor_h 高度进堆。邻居标为已访问。
- 乘积最大子数组 (LeetCode 152)
- 题目:152. 乘积最大子数组
- 买卖股票的最佳时机 (LeetCode 121/122/123/188)【⭐】【🎯】
- 121. 买卖股票的最佳时机
- 122. 买卖股票的最佳时机 II
- 123. 买卖股票的最佳时机 III
- 188. 买卖股票的最佳时机 IV
- 本站题解博客(python3),🎈 1 贪心 维护最低点 + 每天都尝试卖出;2 贪心吃所有上涨波段;3 dp 维护 buy1 sell1 buy2 sell2,其中 buy 是持仓 sell 是拿现金,每天 假设今天买 1 buy1 = max(buy1, -price[i])、今天卖 1 sell1 = max(sell1, buy1 + price[i])、今天买 2 卖 2 同理,最后 return sell2,为什么正确我还没完全理解,总之是神奇的 dp 求解子问题;4 继续 dp 维护 dp[k+1][0/1] 其中 dp[k_i][0] 表示买第 k_i 次,dp[k+i][1] 表示卖第 k_i 次,dp[0][0] 和 dp[0][1] 是留着用作空状态的,继续用上面的方法遍历 n 天的 price、更新 dp 数组。
- 零钱兑换 (LeetCode 322)【⭐】
- 题目:322. 零钱兑换,🎈 dp[i] 代表凑到 i 这个值 需要的最少硬币个数。为了凑到 amount,for i in range(1, amount + 1): for coin in coins: if i - coin >= 0 and dp[i - coin] < max_value - 10: dp[i] = min(dp[i], dp[i - coin] + 1)。
- 二叉树最大路径和 (LeetCode 124)
- 题目:124. 二叉树中的最大路径和,本站题解博客(python3),🎈 其实是 dfs 题,不知道为什么在 dp 里;从 node 出发的 max_gain(node) 为 node.val + max(left_gain, right_gain),而 current_path_sum = left_gain + node + right_gain,最后维护一个全局的 self.max_sum。
- Leetcode-902. 最大为 N 的数字组合
- 题目:902. 最大为 N 的数字组合,本站题解博客(python3),🎈 直接枚举,假设 N 有 L 位,≤ L-1 位的数字随便组;考虑 L 位的数字,从小到大遍历(已经排好序的)digits 列表,如果第 i 位 N[i] > digit,则后面 L-i-1 位随便组;如果 N[i] < digit,则后面的 digit 只会更大,相当于 12xxx > 11234,所以统计结束了;如果 N[i] == digit,则考虑 i+1 位,继续统计;需要维护一下有没有可能用 digits 正好组成 N(是否没有 break),如果有的话,ans 再 += 1。
- 知道秘密的人数
- 鸡蛋掉落
- 题目:LC 887
- 三角形最小路径和
- 分割等和子集
- 题目:416. 分割等和子集
- 最后一块石头的重量 II
- 打家劫舍 III
- 最长有效括号
- 题目:32. 最长有效括号
- 丑数【🎯】
- 题目:264. 丑数 II,313. 超级丑数,🎈 我们去找第 n 个丑数,使用长度为 n 的 dp 数组,dp[i] 表示第 i 个丑数。在 dp 列表里维护 2 指针 3 指针 5 指针,最开始都初始化到 0 的位置。每次它们 ×2 ×3 ×5,值与已经在 dp 列表里的去重,并选最小的作为 dp[i+1]。
-
for i in range(2, n + 1): num2, num3, num5 = dp[p2] * 2, dp[p3] * 3, dp[p5] * 5 dp[i] = min(num2, num3, num5) if dp[i] == num2: p2 += 1 if dp[i] == num3: p3 += 1 # 这里不是 elif,是 if,这样可以自然地去重 if dp[i] == num5: p5 += 1 - 题目:1201. 丑数 III,🎈 这个的做法是二分,以下是大概思路,虽然我还没写过。给我们四个整数:n a b c(abc 不一定是质数),需要找出第 n 个丑数。这个问题被转化为,给定一个整数 n,问 [1, n] 区域内有多少丑数。丑数的个数是:
X/a + X/b + X/c - X/MCM_a_b - X/MCM_a_c - X/MCM_b_c + X/MCM_a_b_c,其中MCM_a_b是 ab 的最小公倍数。
2 双指针 / 滑动窗口:
- 最长无重复子序列 / 子串 (LeetCode 3)【⭐】
- 题目:3. 无重复字符的最长子串,本站题解博客(python3),🎈 滑动窗口,用 dict 维护 char 目前出现的位置,如果新 char 在 dict 内,就用 dict[char] 索引,把目前字串的尾巴切掉。
- 三数之和 (LeetCode 15)【⭐】
- 题目:15. 三数之和,本站题解博客(python3),🎈 先 nums.sort() 排序,然后从前到后确定 ≤ 0 的 num1,通过双指针找合适大小的 num2 num3。
- 两个升序序列的合并【⭐】
- 题目:21. 合并两个有序链表,本站题解博客(python3),🎈 不知道为啥,题解给的是合并 k 个有序列表,k 个可以用最小堆 heapq.heappush(list, (value1, value2)) 来做,2 个有序列表 感觉直接双指针即可。
- 注:如果是数组合并,对应 88. 合并两个有序数组,本站题解博客(python3),🎈 维护三个指针,nums1 nums2 和从后往前的 cur 指针。
- Leetcode-30. 串联所有单词的子串
- 有效三角形的个数 (LeetCode 611)
- 最长回文子串 (LeetCode 5)【⭐】
- 题目:5. 最长回文子串,本站题解博客(python3),🎈 o(n²) 做法,可以枚举回文串中心位置 然后生长出回文串,也可以 dp[i][j] 代表 s[i: j+1] 是否是回文串,如果 s[i] == s[j] 则 dp[i][j] = dp[i+1][j-1]。
3 二分查找:
- Leetcode-81. 搜索旋转排序数组 II,33 搜索旋转排序数组【⭐】
- 题目 (无重复):33. 搜索旋转排序数组
- 题目 (有重复):81. 搜索旋转排序数组 II
- 在排序数组中查找元素的第一个和最后一个位置 (LeetCode 34)
- 有序矩阵中第 K 小的元素 (LeetCode 378)【⭐】【🎯】
- 题目:378. 有序矩阵中第 K 小的元素,本站题解博客(python3),🎈 可以通过 初始位置 = (m-1, 0) 的 o(m+n) 方式统计有多少数小于等于 value。然后开始二分 value,最小值最大值是矩阵的两个角。
- 求浮点数 sqrt(牛顿法/二分)【⭐】
- 题目:69. x 的平方根,🎈 二分轻松又简单,需要 n = (left + right + 1) // 2 。
- 数组中的第 K 个最大元素 (LeetCode 215)【⭐】
- 题目:215. 数组中的第 K 个最大元素,本站题解博客(python3),🎈 o(n) 的 pivot 做法,随机选择基准数,然后将大于、小于、等于 pivot 的元素划分至 big, small, equal 中,对 big 和 small 数组继续找第 K 大、或第 K - len(big) - len(equal) 大数。
再放一个经典快排,python 意外的好写【🎯】:
def quick_sort(arr):
if not arr:
return arr
length = len(arr)
pivot = arr[length // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
if __name__ == '__main__':
arr = [4, 5, 2, 1, 3]
print(quick_sort(arr))
4 贪心算法:
- Leetcode-1221. 分割平衡字符串
- 合并区间 (LeetCode 56)【⭐】【🎯】
- 题目:56. 合并区间,🎈 按区间开始端点(start)升序排列,这样,所有可能重叠的区间都会在数组中相邻。遍历时,若当前区间与 merged[-1] 重叠(curr_start <= last_end),则更新 merged[-1] 的 end = max(merged[-1] 的 end,当前区间 end)。
- 选择最少的数,使这些数的和大于 target。
- 策略:将数组降序排序,依次累加直到大于 target。类似逻辑见 2144. 打折购买糖果的最小开销
- 902. 最多为 N 的数字集合
5 DFS / BFS:
- 全排列 (LeetCode 46)
- 题目:46. 全排列
- 组合 (LeetCode 77)
- 题目:77. 组合
- 岛屿数量【⭐】
- 题目:200. 岛屿数量,本站题解博客(python3),🎈 dfs bfs 都行,map[i][j] = 1 是岛,我们就设 map[i][j] = 0 用水给它淹掉,同时 cnt += 1。dfs 就对 ij 的所有邻居继续调 dfs,bfs 就维护一个队列,队首出队 邻居入队,直到没有 == 1 的邻居。
- 二叉树最近公共祖先 (带父指针)【⭐】
- 题目:1650. 二叉树的最近公共祖先 III(需要 plus 会员)。免费题目:LeetCode Wiki - 1650 题目与题解,本站题解博客(python3),🎈 有父指针就双指针法,p → root →跳→ q → LCA = q → root →跳→ p → LCA = p-LCA + q-LCA + LCA-root,所以它们会相遇在 LCA。
- 注:标准版(不带父指针)为 236. 二叉树的最近公共祖先,本站题解博客(python3),🎈 dfs 搜索,从 root 开始;如果 p q == cur 或 cur 是 None 就 return cur,然后搜索 l = dfs(lch), r = dfs(rch),如果 l r 都有内容就找到了 return cur,否则返回有内容的那个 l / r。
- 字符串解码 (LeetCode 394)
- 题目:394. 字符串解码
- Leetcode-902. 最大为 N 的数字组合
- Leetcode-103. 二叉树的锯齿形层序遍历
- Leetcode-2359. 找到离给定两个节点最近的节点
- 695. 岛屿的最大面积
- 题目:695. 岛屿的最大面积,🎈 dfs bfs 都行,魔改一下那个岛屿数量,把 cnt += 1 变成记录一个面积。
- 301. 删除无效的括号
- 题目:301. 删除无效的括号
6 堆 / 优先队列:
- 合并 K 个升序链表 (LeetCode 23)
- 求字符串出现最多的字符及次数【⭐】
- 说明:这是一道基础面试题,LeetCode 没有完全对应的原题。
- 推荐练习:451. 根据字符出现频率排序,本站题解博客(python3),🎈 题干:将一个字符串中的字符重新排列,出现次数越多的字符,越要排在前面。桶排序:我们创建一个数组(桶),数组的下标代表“频率”,例如 bucket[3] 存储所有出现 3 次的字符,o(n) 遍历一遍统计每个字符出现的频率。
7 栈:
- 有效的括号 (LeetCode 20)
- 题目:20. 有效的括号,🎈 简单的栈匹配。
8 链表:
- Leetcode-148. 排序链表
- 题目:148. 排序链表
- Leetcode-面试题 02.05. 链表求和
- k 个一组翻转链表 (LeetCode 25)
- 删除链表的倒数第 N 个结点
9 其他:
- 有效数字 (LeetCode 65)
- 题目:65. 有效数字,本站题解博客(python3),🎈 状态机,维护一个 dict 作为转移查表,再维护目前状态,最后看是否转移到合法状态,以及中途没有非法输入。
- Leetcode-470. 用 Rand7() 实现 Rand10()
- 题目:470. 用 Rand7() 实现 Rand10(),本站题解博客(python3),🎈 拒绝采样,7×7 = 49 取前 40,剩下的 9 还可以继续 7×9 = 63 取前 60。
- 525. 连续数组(前缀和 + 哈希表,将 0 视为 -1,求和为 0 的最长子数组;或参考 LC 560)
- 题目:525. 连续数组

浙公网安备 33010602011771号