Interview AiBox logo

Ace every interview with Interview AiBox real-time AI assistant

Try Interview AiBoxarrow_forward
8 min readInterview AiBox Team

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:

  1. Two Pointers
  2. Sliding Window
  3. Hash Table
  4. Depth-First Search
  5. Breadth-First Search
  6. Binary Search
  7. Dynamic Programming
  8. Backtracking
  9. Heap/Priority Queue
  10. 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 = 9

Core 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:

  1. Iterate through the array, for each element nums[i]
  2. Calculate complement = target - nums[i]
  3. Check if complement exists in the hash table
  4. 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:

  1. Fast lookup: Hash table
  2. Fast order adjustment: Doubly linked list

Data Structure Combination:

  • HashMap<Integer, Node>: Key-to-node mapping for O(1) lookup
  • DoublyLinkedList: 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 LinkedHashMap simplify 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: 1

Core Approach

This is a classic connected components counting problem.

Algorithm:

  1. Traverse each cell in the grid
  2. When encountering '1', increment count and use DFS/BFS to mark the entire island as visited (change to '0')
  3. 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 count

Java (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->4

Core 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.next

Java (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: false

Core Approach

Use a stack to match parentheses:

  1. When encountering an opening bracket, push to stack
  2. When encountering a closing bracket, check if it matches the stack top
  3. 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 stack

Java:

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 = 6

Core 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_sum

Java:

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 AiBox logo

Interview 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.

Share this article

Copy the link or share to social platforms

External

Read Next

Top 20 LeetCode Questions You Must Know in 2026 | Interview AiBox