Ace every interview with Interview AiBoxInterview AiBox real-time AI assistant
Top 20 LeetCode Questions You Must Know in 2026
A curated list of the 20 most frequently asked LeetCode interview questions with detailed explanations, Python/Java implementations, and complexity analysis. Focus on patterns, not memorization.
- sellLeetcode
- sellInterview questions
- sellAlgorithm
- sellData structure
- sellCoding
Top 20 LeetCode Questions You Must Know in 2026
Grinded hundreds of problems but still fail interviews? The issue isn't quantity—it's approach.
Many candidates solve 300+ problems but freeze when facing a new question. Why? Because they memorized answers instead of understanding patterns.
This article curates the 20 most frequently asked LeetCode problems. We don't just give you solutions—we help you build a problem-solving framework. Master these patterns, and you'll handle any variation with confidence.
Why These 20 Questions?
We analyzed interview data from Google, Meta, Amazon, Apple, Microsoft, and other top companies over the past two years. These 20 questions:
- Highest frequency: Cover 80%+ of interview scenarios
- Strong representation: Each represents a classic problem category
- Moderate difficulty: Mostly Medium with some Hard, matching real interview difficulty
More importantly, these 20 questions cover 10 core problem-solving patterns:
- Two Pointers
- Sliding Window
- Hash Table
- Depth-First Search
- Breadth-First Search
- Binary Search
- Dynamic Programming
- Backtracking
- Heap/Priority Queue
- System Design
Two Sum
Difficulty: Easy
Frequency: ⭐⭐⭐⭐⭐
Core Pattern: Hash Table
Problem Description
Given an array of integers nums and a target value target, find two numbers that add up to the target and return their indices.
Example:
Input: nums = [2, 7, 11, 15], target = 9
Output: [0, 1]
Explanation: nums[0] + nums[1] = 2 + 7 = 9Core Approach
Brute force is O(n²), but we can optimize to O(n) using a hash table.
Key Insight: For each number num, we only need to know if target - num exists in the array.
Algorithm:
- Iterate through the array, for each element
nums[i] - Calculate
complement = target - nums[i] - Check if
complementexists in the hash table - If yes, return result; if no, add
nums[i]to the hash table
Implementation
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[]{};
}Complexity Analysis
- Time: O(n), single pass through the array
- Space: O(n), hash table stores at most n elements
Variations
- Three Sum
- Four Sum
- Two Sum II - Input Array Is Sorted
LRU Cache
Difficulty: Medium
Frequency: ⭐⭐⭐⭐⭐
Core Pattern: Design + Doubly Linked List + Hash Table
Problem Description
Design an LRU (Least Recently Used) cache that supports get and put operations in O(1) time.
Example:
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1); // returns 1, cache becomes {2=2, 1=1}
lRUCache.put(3, 3); // evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2); // returns -1 (not found)Core Approach
LRU's core is managing "recently used" order. We need:
- Fast lookup: Hash table
- Fast order adjustment: Doubly linked list
Data Structure Combination:
HashMap<Integer, Node>: Key-to-node mapping for O(1) lookupDoublyLinkedList: Maintains usage order, head is most recent, tail is least recent
Implementation
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);
}
}
}Complexity Analysis
- Time: O(1) for both get and put
- Space: O(capacity)
Interview Points
- Why doubly linked list instead of singly linked list?
- How to handle edge cases (capacity 0, empty cache)?
- Can Java's
LinkedHashMapsimplify the implementation?
Number of Islands
Difficulty: Medium
Frequency: ⭐⭐⭐⭐⭐
Core Pattern: DFS/BFS + Grid Graph
Problem Description
Given a 2D grid of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and formed by connecting adjacent lands horizontally or vertically.
Example:
Input:
11110
11010
11000
00000
Output: 1Core Approach
This is a classic connected components counting problem.
Algorithm:
- Traverse each cell in the grid
- When encountering '1', increment count and use DFS/BFS to mark the entire island as visited (change to '0')
- Continue until all cells are visited
Implementation
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';
}
}
}
}Complexity Analysis
- Time: O(m×n), each cell visited at most once
- Space: O(m×n), worst case for DFS recursion stack or BFS queue
Variations
- Max Area of Island
- Surrounded Regions
- Number of Distinct Islands
Merge Two Sorted Lists
Difficulty: Easy
Frequency: ⭐⭐⭐⭐⭐
Core Pattern: Two Pointers + Linked List
Problem Description
Merge two sorted linked lists into one sorted list.
Example:
Input: l1 = 1->2->4, l2 = 1->3->4
Output: 1->1->2->3->4->4Core Approach
Use two pointers to traverse both lists, always choosing the smaller node to add to the result.
Tip: Use a dummy node to simplify boundary handling.
Implementation
Python (Iterative):
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 (Recursive):
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;
}
}Complexity Analysis
- Time: O(n+m), n and m are the lengths of the two lists
- Space: Iterative O(1), Recursive O(n+m) (stack space)
Valid Parentheses
Difficulty: Easy
Frequency: ⭐⭐⭐⭐⭐
Core Pattern: Stack
Problem Description
Given a string containing only parentheses, determine if it's valid.
Example:
Input: "()[]{}"
Output: true
Input: "([)]"
Output: falseCore Approach
Use a stack to match parentheses:
- When encountering an opening bracket, push to stack
- When encountering a closing bracket, check if it matches the stack top
- Stack should be empty at the end
Implementation
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();
}Complexity Analysis
- Time: O(n)
- Space: O(n)
Maximum Subarray
Difficulty: Medium
Frequency: ⭐⭐⭐⭐⭐
Core Pattern: Dynamic Programming / Kadane's Algorithm
Problem Description
Find the contiguous subarray with the largest sum.
Example:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6Core Approach
Kadane's Algorithm: For each position, choose "maximum sum ending at current element".
State Transition:
dp[i] = max(nums[i], dp[i-1] + nums[i])Implementation
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;
}Complexity Analysis
- Time: O(n)
- Space: O(1)
Binary Tree Level Order Traversal
Difficulty: Medium
Frequency: ⭐⭐⭐⭐⭐
Core Pattern: BFS
Problem Description
Given a binary tree, return its level order traversal
Interview AiBoxInterview AiBox — Interview Copilot
Beyond Prep — Real-Time Interview Support
Interview AiBox provides real-time on-screen hints, AI mock interviews, and smart debriefs — so every answer lands with confidence.
AI Reading Assistant
Send to your preferred AI
Smart Summary
Deep Analysis
Key Topics
Insights
Share this article
Copy the link or share to social platforms