Interview AiBoxInterview AiBox 实时 AI 助手,让你自信应答每一场面试
Top 20 LeetCode高频面试题详解(附代码与思路)
精选20道最高频LeetCode面试题,每题包含题目描述、核心思路、Python/Java代码实现和复杂度分析,助你理解解题模式而非死记硬背。
- sellLeetcode
- sellInterview questions
- sellAlgorithm
- sellData structure
- sellCoding
Top 20 LeetCode高频面试题详解(附代码与思路)
刷题无数,面试还是挂?问题可能不在数量,而在方法。
很多候选人刷了300+道题,面试时遇到新题还是懵。为什么?因为他们记住了答案,而不是理解了模式。
这篇文章精选20道最高频LeetCode题目,不只是给你答案,而是帮你建立解题思维框架。掌握了这些模式,你就能举一反三,应对任何变体。
为什么是这20道题?
我们分析了Google、Meta、Amazon、Apple、Microsoft等大厂近两年的面试数据,这20道题:
- 出现频率最高:覆盖80%+的面试场景
- 代表性强:每道题代表一类经典问题
- 难度适中:Medium为主,Hard为辅,符合真实面试难度
更重要的是,这20道题覆盖了10大核心解题模式:
- 双指针
- 滑动窗口
- 哈希表
- 深度优先搜索
- 广度优先搜索
- 二分查找
- 动态规划
- 回溯
- 堆/优先队列
- 设计类
Two Sum(两数之和)
难度:Easy
出现频率:⭐⭐⭐⭐⭐
核心模式:哈希表
题目描述
给定一个整数数组 nums 和一个目标值 target,在数组中找出和为目标值的两个数,返回它们的索引。
示例:
输入:nums = [2, 7, 11, 15], target = 9
输出:[0, 1]
解释:nums[0] + nums[1] = 2 + 7 = 9核心思路
暴力解法是O(n²),但我们可以用哈希表优化到O(n)。
关键洞察:对于每个数num,我们只需要知道target - num是否在数组中。
算法流程:
- 遍历数组,对于每个元素
nums[i] - 计算
complement = target - nums[i] - 检查
complement是否在哈希表中 - 如果在,返回结果;如果不在,将
nums[i]加入哈希表
代码实现
Python:
def twoSum(nums: List[int], target: int) -> List[int]:
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []Java:
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (seen.containsKey(complement)) {
return new int[]{seen.get(complement), i};
}
seen.put(nums[i], i);
}
return new int[]{};
}复杂度分析
- 时间复杂度:O(n),只需遍历一次数组
- 空间复杂度:O(n),哈希表最多存储n个元素
变体题目
- Three Sum(三数之和)
- Four Sum(四数之和)
- Two Sum II - Input Array Is Sorted(有序数组的两数之和)
LRU Cache(LRU缓存)
难度:Medium
出现频率:⭐⭐⭐⭐⭐
核心模式:设计类 + 双向链表 + 哈希表
题目描述
设计一个LRU(最近最少使用)缓存,支持get和put操作,要求O(1)时间复杂度。
示例:
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1,缓存变为 {2=2, 1=1}
lRUCache.put(3, 3); // 淘汰 key 2,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1(未找到)核心思路
LRU的核心是"最近使用"的顺序管理。我们需要:
- 快速查找:哈希表
- 快速调整顺序:双向链表
数据结构组合:
HashMap<Integer, Node>:key到节点的映射,O(1)查找DoublyLinkedList:维护使用顺序,头部是最近使用的,尾部是最久未使用的
代码实现
Python:
class Node:
def __init__(self, key=0, val=0):
self.key = key
self.val = val
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.cache = {}
self.head = Node()
self.tail = Node()
self.head.next = self.tail
self.tail.prev = self.head
def _remove(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def _add_to_front(self, node):
node.next = self.head.next
node.prev = self.head
self.head.next.prev = node
self.head.next = node
def get(self, key: int) -> int:
if key not in self.cache:
return -1
node = self.cache[key]
self._remove(node)
self._add_to_front(node)
return node.val
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
node.val = value
self._remove(node)
self._add_to_front(node)
else:
if len(self.cache) >= self.capacity:
lru = self.tail.prev
self._remove(lru)
del self.cache[lru.key]
node = Node(key, value)
self.cache[key] = node
self._add_to_front(node)Java:
class LRUCache {
class Node {
int key, val;
Node prev, next;
Node(int key, int val) {
this.key = key;
this.val = val;
}
}
private Map<Integer, Node> cache;
private Node head, tail;
private int capacity;
public LRUCache(int capacity) {
this.capacity = capacity;
cache = new HashMap<>();
head = new Node(0, 0);
tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
}
private void remove(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void addToFront(Node node) {
node.next = head.next;
node.prev = head;
head.next.prev = node;
head.next = node;
}
public int get(int key) {
if (!cache.containsKey(key)) return -1;
Node node = cache.get(key);
remove(node);
addToFront(node);
return node.val;
}
public void put(int key, int value) {
if (cache.containsKey(key)) {
Node node = cache.get(key);
node.val = value;
remove(node);
addToFront(node);
} else {
if (cache.size() >= capacity) {
Node lru = tail.prev;
remove(lru);
cache.remove(lru.key);
}
Node node = new Node(key, value);
cache.put(key, node);
addToFront(node);
}
}
}复杂度分析
- 时间复杂度:get和put都是O(1)
- 空间复杂度:O(capacity)
面试要点
- 为什么用双向链表而不是单向链表?
- 如何处理边界条件(容量为0、空缓存等)?
- 能否用Java的
LinkedHashMap简化实现?
Number of Islands(岛屿数量)
难度:Medium
出现频率:⭐⭐⭐⭐⭐
核心模式:DFS/BFS + 网格图
题目描述
给定一个由'1'(陆地)和'0'(水)组成的二维网格,计算岛屿的数量。岛屿被水包围,由相邻的陆地连接而成(水平或垂直方向)。
示例:
输入:
11110
11010
11000
00000
输出:1核心思路
这是一道经典的连通分量计数问题。
算法流程:
- 遍历网格的每个位置
- 遇到'1'时,岛屿数量+1,然后用DFS/BFS将整个岛屿标记为已访问(改为'0')
- 继续遍历,直到所有位置都被访问
代码实现
Python(DFS):
def numIslands(grid: List[List[str]]) -> int:
if not grid:
return 0
rows, cols = len(grid), len(grid[0])
count = 0
def dfs(r, c):
if r < 0 or r >= rows or c < 0 or c >= cols or grid[r][c] == '0':
return
grid[r][c] = '0'
dfs(r+1, c)
dfs(r-1, c)
dfs(r, c+1)
dfs(r, c-1)
for r in range(rows):
for c in range(cols):
if grid[r][c] == '1':
count += 1
dfs(r, c)
return countJava(BFS):
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) return 0;
int rows = grid.length, cols = grid[0].length;
int count = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == '1') {
count++;
bfs(grid, r, c);
}
}
}
return count;
}
private void bfs(char[][] grid, int r, int c) {
int rows = grid.length, cols = grid[0].length;
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{r, c});
grid[r][c] = '0';
int[][] dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}};
while (!queue.isEmpty()) {
int[] cell = queue.poll();
for (int[] dir : dirs) {
int nr = cell[0] + dir[0];
int nc = cell[1] + dir[1];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && grid[nr][nc] == '1') {
queue.offer(new int[]{nr, nc});
grid[nr][nc] = '0';
}
}
}
}复杂度分析
- 时间复杂度:O(m×n),每个格子最多访问一次
- 空间复杂度:O(m×n),DFS递归栈或BFS队列的最坏情况
变体题目
- Max Area of Island(岛屿的最大面积)
- Surrounded Regions(被包围的区域)
- Number of Distinct Islands(不同岛屿的数量)
Merge Two Sorted Lists(合并两个有序链表)
难度:Easy
出现频率:⭐⭐⭐⭐⭐
核心模式:双指针 + 链表
题目描述
将两个升序链表合并为一个新的升序链表并返回。
示例:
输入:l1 = 1->2->4, l2 = 1->3->4
输出:1->1->2->3->4->4核心思路
使用双指针分别遍历两个链表,每次选择较小的节点加入结果链表。
技巧:使用虚拟头节点(dummy node)简化边界处理。
代码实现
Python(迭代):
def mergeTwoLists(l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode(0)
curr = dummy
while l1 and l2:
if l1.val <= l2.val:
curr.next = l1
l1 = l1.next
else:
curr.next = l2
l2 = l2.next
curr = curr.next
curr.next = l1 if l1 else l2
return dummy.nextJava(递归):
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val <= l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}复杂度分析
- 时间复杂度:O(n+m),n和m是两个链表的长度
- 空间复杂度:迭代O(1),递归O(n+m)(栈空间)
Valid Parentheses(有效的括号)
难度:Easy
出现频率:⭐⭐⭐⭐⭐
核心模式:栈
题目描述
给定一个只包含括号的字符串,判断括号是否有效。
示例:
输入:"()[]{}"
输出:true
输入:"([)]"
输出:false核心思路
使用栈来匹配括号:
- 遇到左括号,入栈
- 遇到右括号,检查栈顶是否匹配
- 最后栈应该为空
代码实现
Python:
def isValid(s: str) -> bool:
stack = []
mapping = {')': '(', ']': '[', '}': '{'}
for char in s:
if char in mapping:
if not stack or stack[-1] != mapping[char]:
return False
stack.pop()
else:
stack.append(char)
return not stackJava:
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
Map<Character, Character> map = Map.of(')', '(', ']', '[', '}', '{');
for (char c : s.toCharArray()) {
if (map.containsKey(c)) {
if (stack.isEmpty() || stack.pop() != map.get(c)) {
return false;
}
} else {
stack.push(c);
}
}
return stack.isEmpty();
}复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(n)
Maximum Subarray(最大子数组和)
难度:Medium
出现频率:⭐⭐⭐⭐⭐
核心模式:动态规划 / Kadane算法
题目描述
找到具有最大和的连续子数组,返回其和。
示例:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6核心思路
Kadane算法:对于每个位置,选择"以当前元素结尾的最大和"。
状态转移:
dp[i] = max(nums[i], dp[i-1] + nums[i])代码实现
Python:
def maxSubArray(nums: List[int]) -> int:
max_sum = curr_sum = nums[0]
for num in nums[1:]:
curr_sum = max(num, curr_sum + num)
max_sum = max(max_sum, curr_sum)
return max_sumJava:
public int maxSubArray(int[] nums) {
int maxSum = nums[0], currSum = nums[0];
for (int i = 1; i < nums.length; i++) {
currSum = Math.max(nums[i], currSum + nums[i]);
maxSum = Math.max(maxSum, currSum);
}
return maxSum;
}复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(1)
Interview AiBoxInterview AiBox — 面试搭档
不只是准备,更是实时陪练
Interview AiBox 在面试过程中提供实时屏幕提示、AI 模拟面试和智能复盘,让你每一次回答都更有信心。
AI 助读
一键发送到常用 AI
智能总结
深度解读
考点定位
思路启发
分享文章
复制链接,或一键分享到常用平台