The 47 most common coding interview problems with clean solutions, step-by-step approaches, and complexity analysis. Organized by pattern so you learn how to recognize and solve each type.
Every coding interview follows the same playbook. The interviewer gives you a problem, you think out loud, write code on a whiteboard or shared editor, and then walk through test cases. The problems themselves are not random. They come from a small set of well-known patterns that repeat across companies.
This guide covers 47 of the most frequently asked coding interview problems, organized by the pattern they test. Learning these patterns is more valuable than memorizing individual solutions because interviewers regularly modify the problems. If you understand why a hash map solves Two Sum, you can solve any variation they throw at you.
A typical coding round lasts 45 minutes. You will get one or two problems (usually one medium, or one easy and one medium). The interviewer expects you to spend the first few minutes clarifying the problem and discussing your approach before writing any code. Jumping straight into code is one of the most common mistakes.
After coding, you are expected to trace through your solution with a test case, identify edge cases, and analyze the time and space complexity. The interviewer is evaluating four things: problem-solving ability, code quality, communication, and how you handle feedback.
The 47 problems below are grouped into 10 patterns. Each pattern is a general technique that applies to many problems. Here is a quick overview of when to use each one:
Arrays & Hashing
7 problems
Two Pointers
5 problems
Sliding Window
4 problems
Stack
4 problems
Binary Search
4 problems
Linked List
5 problems
Trees
6 problems
Dynamic Programming
6 problems
Graphs
3 problems
Intervals & Greedy
3 problems
For each problem, you will find the exact approach you would explain to an interviewer, clean Python code you could write on a whiteboard, and the time and space complexity. The goal is not to memorize these solutions but to internalize the patterns so you can derive solutions to new problems on the spot.
If you want to practice these problems interactively with an AI interviewer that asks follow-up questions and scores your performance, try Crackr for free.
47 problems
Given an array of integers and a target, return the indices of two numbers that add up to the target.
Input: nums = [2,7,11,15], target = 9 Output: [0,1]
Approach
def two_sum(nums, target):
seen = {}
for i, num in enumerate(nums):
comp = target - num
if comp in seen:
return [seen[comp], i]
seen[num] = iGiven an integer array, return true if any value appears at least twice.
Input: nums = [1,2,3,1] Output: true
Approach
def contains_duplicate(nums):
seen = set()
for num in nums:
if num in seen:
return True
seen.add(num)
return FalseGiven two strings s and t, return true if t is an anagram of s.
Input: s = "anagram", t = "nagaram" Output: true
Approach
def is_anagram(s, t):
if len(s) != len(t):
return False
count = {}
for c in s:
count[c] = count.get(c, 0) + 1
for c in t:
count[c] = count.get(c, 0) - 1
if count[c] < 0:
return False
return TrueGiven an array of strings, group the anagrams together.
Input: ["eat","tea","tan","ate","nat","bat"] Output: [["eat","tea","ate"],["tan","nat"],["bat"]]
Approach
def group_anagrams(strs):
groups = {}
for s in strs:
key = tuple(sorted(s))
groups.setdefault(key, []).append(s)
return list(groups.values())Given an integer array and k, return the k most frequent elements.
Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]
Approach
def top_k_frequent(nums, k):
count = {}
for n in nums:
count[n] = count.get(n, 0) + 1
buckets = [[] for _ in range(len(nums) + 1)]
for num, freq in count.items():
buckets[freq].append(num)
result = []
for i in range(len(buckets) - 1, -1, -1):
for num in buckets[i]:
result.append(num)
if len(result) == k:
return resultReturn an array where each element is the product of all other elements. No division allowed.
Input: nums = [1,2,3,4] Output: [24,12,8,6]
Approach
def product_except_self(nums):
n = len(nums)
result = [1] * n
prefix = 1
for i in range(n):
result[i] = prefix
prefix *= nums[i]
suffix = 1
for i in range(n - 1, -1, -1):
result[i] *= suffix
suffix *= nums[i]
return resultGiven an unsorted array, find the length of the longest consecutive elements sequence in O(n) time.
Input: nums = [100,4,200,1,3,2] Output: 4 (sequence: [1,2,3,4])
Approach
def longest_consecutive(nums):
num_set = set(nums)
longest = 0
for num in num_set:
if num - 1 not in num_set:
length = 1
while num + length in num_set:
length += 1
longest = max(longest, length)
return longestGiven a string, determine if it is a palindrome considering only alphanumeric characters (case insensitive).
Input: "A man, a plan, a canal: Panama" Output: true
Approach
def is_palindrome(s):
left, right = 0, len(s) - 1
while left < right:
while left < right and not s[left].isalnum():
left += 1
while left < right and not s[right].isalnum():
right -= 1
if s[left].lower() != s[right].lower():
return False
left += 1
right -= 1
return TrueGiven a sorted array and a target, return indices of two numbers that add up to the target. Use O(1) space.
Input: numbers = [2,7,11,15], target = 9 Output: [1,2]
Approach
def two_sum_ii(numbers, target):
left, right = 0, len(numbers) - 1
while left < right:
total = numbers[left] + numbers[right]
if total == target:
return [left + 1, right + 1]
elif total < target:
left += 1
else:
right -= 1Find all unique triplets in the array that sum to zero.
Input: nums = [-1,0,1,2,-1,-4] Output: [[-1,-1,2],[-1,0,1]]
Approach
def three_sum(nums):
nums.sort()
result = []
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue
left, right = i + 1, len(nums) - 1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total == 0:
result.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1
left += 1
right -= 1
elif total < 0:
left += 1
else:
right -= 1
return resultGiven n vertical lines, find two lines that together with the x-axis form a container holding the most water.
Input: height = [1,8,6,2,5,4,8,3,7] Output: 49
Approach
def max_area(height):
left, right = 0, len(height) - 1
best = 0
while left < right:
area = min(height[left], height[right]) * (right - left)
best = max(best, area)
if height[left] < height[right]:
left += 1
else:
right -= 1
return bestGiven n non-negative integers representing an elevation map, compute how much water it can trap after rain.
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1] Output: 6
Approach
def trap(height):
left, right = 0, len(height) - 1
left_max = right_max = water = 0
while left < right:
if height[left] < height[right]:
left_max = max(left_max, height[left])
water += left_max - height[left]
left += 1
else:
right_max = max(right_max, height[right])
water += right_max - height[right]
right -= 1
return waterGiven an array of prices, find the maximum profit from one buy and one sell (buy before sell).
Input: prices = [7,1,5,3,6,4] Output: 5 (buy at 1, sell at 6)
Approach
def max_profit(prices):
min_price = float('inf')
max_profit = 0
for price in prices:
min_price = min(min_price, price)
max_profit = max(max_profit, price - min_price)
return max_profitFind the length of the longest substring without repeating characters.
Input: s = "abcabcbb"
Output: 3 ("abc")Approach
def length_of_longest_substring(s):
seen = set()
left = result = 0
for right in range(len(s)):
while s[right] in seen:
seen.remove(s[left])
left += 1
seen.add(s[right])
result = max(result, right - left + 1)
return resultGiven a string and k, find the longest substring where you can replace at most k characters to make all characters the same.
Input: s = "AABABBA", k = 1 Output: 4
Approach
def character_replacement(s, k):
count = {}
left = max_freq = result = 0
for right in range(len(s)):
count[s[right]] = count.get(s[right], 0) + 1
max_freq = max(max_freq, count[s[right]])
if (right - left + 1) - max_freq > k:
count[s[left]] -= 1
left += 1
result = max(result, right - left + 1)
return resultGiven strings s and t, find the minimum window in s that contains all characters of t.
Input: s = "ADOBECODEBANC", t = "ABC" Output: "BANC"
Approach
def min_window(s, t):
need = {}
for c in t:
need[c] = need.get(c, 0) + 1
missing = len(t)
left = start = 0
best = float('inf')
for right, c in enumerate(s):
if need.get(c, 0) > 0:
missing -= 1
need[c] = need.get(c, 0) - 1
while missing == 0:
if right - left + 1 < best:
best = right - left + 1
start = left
need[s[left]] += 1
if need[s[left]] > 0:
missing += 1
left += 1
return "" if best == float('inf') else s[start:start + best]Given a string containing just '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
Input: s = "()[]{}"
Output: trueApproach
def is_valid(s):
stack = []
pairs = {')': '(', '}': '{', ']': '['}
for c in s:
if c in pairs:
if not stack or stack[-1] != pairs[c]:
return False
stack.pop()
else:
stack.append(c)
return len(stack) == 0Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
push(-2), push(0), push(-3) getMin() returns -3, pop(), getMin() returns -2
Approach
class MinStack:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self, val):
self.stack.append(val)
val = min(val, self.min_stack[-1] if self.min_stack else val)
self.min_stack.append(val)
def pop(self):
self.stack.pop()
self.min_stack.pop()
def top(self):
return self.stack[-1]
def getMin(self):
return self.min_stack[-1]Evaluate an arithmetic expression in Reverse Polish Notation (postfix).
Input: tokens = ["2","1","+","3","*"] Output: 9 ((2+1)*3)
Approach
def eval_rpn(tokens):
stack = []
for t in tokens:
if t in "+-*/":
b, a = stack.pop(), stack.pop()
if t == '+': stack.append(a + b)
elif t == '-': stack.append(a - b)
elif t == '*': stack.append(a * b)
else: stack.append(int(a / b))
else:
stack.append(int(t))
return stack[0]Given daily temperatures, return an array where each element is the number of days until a warmer temperature.
Input: temps = [73,74,75,71,69,72,76,73] Output: [1,1,4,2,1,1,0,0]
Approach
def daily_temperatures(temperatures):
n = len(temperatures)
result = [0] * n
stack = []
for i in range(n):
while stack and temperatures[i] > temperatures[stack[-1]]:
j = stack.pop()
result[j] = i - j
stack.append(i)
return resultGiven a sorted array and a target, return the index of the target or -1 if not found.
Input: nums = [-1,0,3,5,9,12], target = 9 Output: 4
Approach
def binary_search(nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1Search for a target in an m x n matrix where each row is sorted and the first integer of each row is greater than the last of the previous row.
Input: matrix = [[1,3,5],[10,11,16],[23,30,34]], target = 3 Output: true
Approach
def search_matrix(matrix, target):
rows, cols = len(matrix), len(matrix[0])
left, right = 0, rows * cols - 1
while left <= right:
mid = (left + right) // 2
val = matrix[mid // cols][mid % cols]
if val == target:
return True
elif val < target:
left = mid + 1
else:
right = mid - 1
return FalseKoko has n piles of bananas and h hours. Find the minimum eating speed k (bananas/hour) to eat all bananas in time.
Input: piles = [3,6,7,11], h = 8 Output: 4
Approach
import math
def min_eating_speed(piles, h):
left, right = 1, max(piles)
while left < right:
mid = (left + right) // 2
hours = sum(math.ceil(p / mid) for p in piles)
if hours <= h:
right = mid
else:
left = mid + 1
return leftSearch for a target in a rotated sorted array (no duplicates). Return its index or -1.
Input: nums = [4,5,6,7,0,1,2], target = 0 Output: 4
Approach
def search(nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
if nums[left] <= nums[mid]:
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
else:
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
return -1Reverse a singly linked list.
Input: 1 -> 2 -> 3 -> 4 -> 5 Output: 5 -> 4 -> 3 -> 2 -> 1
Approach
def reverse_list(head):
prev = None
curr = head
while curr:
next_node = curr.next
curr.next = prev
prev = curr
curr = next_node
return prevMerge two sorted linked lists into one sorted list.
Input: 1->2->4, 1->3->4 Output: 1->1->2->3->4->4
Approach
def merge_two_lists(l1, l2):
dummy = ListNode()
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 or l2
return dummy.nextDetermine if a linked list has a cycle.
Input: 3 -> 2 -> 0 -> -4 -> (back to 2) Output: true
Approach
def has_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return FalseRemove the nth node from the end of a linked list and return its head.
Input: 1->2->3->4->5, n = 2 Output: 1->2->3->5
Approach
def remove_nth_from_end(head, n):
dummy = ListNode(0, head)
slow = fast = dummy
for _ in range(n + 1):
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummy.nextReorder a linked list from L0 -> L1 -> ... -> Ln to L0 -> Ln -> L1 -> Ln-1 -> ...
Input: 1->2->3->4->5 Output: 1->5->2->4->3
Approach
def reorder_list(head):
slow = fast = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
# Reverse second half
prev, curr = None, slow.next
slow.next = None
while curr:
nxt = curr.next
curr.next = prev
prev = curr
curr = nxt
# Merge two halves
first, second = head, prev
while second:
tmp1, tmp2 = first.next, second.next
first.next = second
second.next = tmp1
first, second = tmp1, tmp2Invert a binary tree (mirror it).
Input: 4 Output: 4
/ \ / \
2 7 7 2
/ \ / \ / \ / \
1 3 6 9 9 6 3 1Approach
def invert_tree(root):
if not root:
return None
root.left, root.right = root.right, root.left
invert_tree(root.left)
invert_tree(root.right)
return rootFind the maximum depth (number of nodes along the longest root-to-leaf path) of a binary tree.
Input: [3,9,20,null,null,15,7] Output: 3
Approach
def max_depth(root):
if not root:
return 0
return 1 + max(max_depth(root.left), max_depth(root.right))Check if two binary trees are structurally identical with the same values.
Input: p = [1,2,3], q = [1,2,3] Output: true
Approach
def is_same_tree(p, q):
if not p and not q:
return True
if not p or not q or p.val != q.val:
return False
return is_same_tree(p.left, q.left) and is_same_tree(p.right, q.right)Check if tree t is a subtree of tree s.
Input: s = [3,4,5,1,2], t = [4,1,2] Output: true
Approach
def is_subtree(root, sub_root):
if not root:
return False
if is_same_tree(root, sub_root):
return True
return is_subtree(root.left, sub_root) or is_subtree(root.right, sub_root)Find the lowest common ancestor of two nodes in a Binary Search Tree.
Input: root = [6,2,8,0,4,7,9], p = 2, q = 8 Output: 6
Approach
def lowest_common_ancestor(root, p, q):
while root:
if p.val < root.val and q.val < root.val:
root = root.left
elif p.val > root.val and q.val > root.val:
root = root.right
else:
return rootDetermine if a binary tree is a valid BST.
Input: [5,1,4,null,null,3,6] Output: false (4 is right child of 5 but has 3)
Approach
def is_valid_bst(root, lo=float('-inf'), hi=float('inf')):
if not root:
return True
if root.val <= lo or root.val >= hi:
return False
return (is_valid_bst(root.left, lo, root.val) and
is_valid_bst(root.right, root.val, hi))You can climb 1 or 2 steps at a time. How many distinct ways can you climb n steps?
Input: n = 5 Output: 8
Approach
def climb_stairs(n):
if n <= 2:
return n
a, b = 1, 2
for _ in range(3, n + 1):
a, b = b, a + b
return bRob houses along a street. Adjacent houses have connected alarms. Maximize the amount you can rob without triggering alarms.
Input: nums = [2,7,9,3,1] Output: 12 (rob houses 1, 3, 5)
Approach
def rob(nums):
if len(nums) <= 2:
return max(nums)
prev2, prev1 = nums[0], max(nums[0], nums[1])
for i in range(2, len(nums)):
prev2, prev1 = prev1, max(prev1, prev2 + nums[i])
return prev1Given coin denominations and a target amount, find the fewest number of coins needed. Return -1 if impossible.
Input: coins = [1,5,10,25], amount = 30 Output: 2 (25 + 5)
Approach
def coin_change(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
for coin in coins:
if coin <= i:
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1Find the length of the longest strictly increasing subsequence.
Input: nums = [10,9,2,5,3,7,101,18] Output: 4 ([2,3,7,101])
Approach
import bisect
def length_of_lis(nums):
tails = []
for num in nums:
pos = bisect.bisect_left(tails, num)
if pos == len(tails):
tails.append(num)
else:
tails[pos] = num
return len(tails)Given a string and a dictionary, determine if the string can be segmented into dictionary words.
Input: s = "leetcode", wordDict = ["leet","code"] Output: true
Approach
def word_break(s, word_dict):
words = set(word_dict)
dp = [False] * (len(s) + 1)
dp[0] = True
for i in range(1, len(s) + 1):
for j in range(i):
if dp[j] and s[j:i] in words:
dp[i] = True
break
return dp[len(s)]Find the contiguous subarray with the largest sum.
Input: nums = [-2,1,-3,4,-1,2,1,-5,4] Output: 6 ([4,-1,2,1])
Approach
def max_sub_array(nums):
max_sum = current = nums[0]
for num in nums[1:]:
current = max(num, current + num)
max_sum = max(max_sum, current)
return max_sumGiven a 2D grid of '1's (land) and '0's (water), count the number of islands.
Input: grid = [ ["1","1","0"], ["0","1","0"], ["0","0","1"] ] Output: 2
Approach
def num_islands(grid):
count = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == "1":
count += 1
dfs(grid, i, j)
return count
def dfs(grid, i, j):
if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]) or grid[i][j] != "1":
return
grid[i][j] = "0"
for di, dj in [(1,0),(-1,0),(0,1),(0,-1)]:
dfs(grid, i + di, j + dj)Given a reference to a node in a connected undirected graph, return a deep copy of the graph.
Input: node with neighbors Output: deep copy of entire graph
Approach
def clone_graph(node):
if not node:
return None
clones = {}
def dfs(n):
if n in clones:
return clones[n]
copy = Node(n.val)
clones[n] = copy
for neighbor in n.neighbors:
copy.neighbors.append(dfs(neighbor))
return copy
return dfs(node)There are n courses with prerequisites. Determine if you can finish all courses (detect cycle in directed graph).
Input: numCourses = 2, prerequisites = [[1,0]] Output: true
Approach
from collections import deque
def can_finish(num_courses, prerequisites):
graph = [[] for _ in range(num_courses)]
in_degree = [0] * num_courses
for course, prereq in prerequisites:
graph[prereq].append(course)
in_degree[course] += 1
queue = deque(i for i in range(num_courses) if in_degree[i] == 0)
count = 0
while queue:
node = queue.popleft()
count += 1
for neighbor in graph[node]:
in_degree[neighbor] -= 1
if in_degree[neighbor] == 0:
queue.append(neighbor)
return count == num_coursesGiven an array of intervals, merge all overlapping intervals.
Input: [[1,3],[2,6],[8,10],[15,18]] Output: [[1,6],[8,10],[15,18]]
Approach
def merge(intervals):
intervals.sort()
merged = [intervals[0]]
for start, end in intervals[1:]:
if start <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], end)
else:
merged.append([start, end])
return mergedFind the minimum number of intervals to remove to make the rest non-overlapping.
Input: [[1,2],[2,3],[3,4],[1,3]] Output: 1 (remove [1,3])
Approach
def erase_overlap_intervals(intervals):
intervals.sort(key=lambda x: x[1])
count = 0
prev_end = float('-inf')
for start, end in intervals:
if start < prev_end:
count += 1
else:
prev_end = end
return countGiven meeting time intervals, find the minimum number of conference rooms required.
Input: [[0,30],[5,10],[15,20]] Output: 2
Approach
def min_meeting_rooms(intervals):
starts = sorted(i[0] for i in intervals)
ends = sorted(i[1] for i in intervals)
rooms = max_rooms = 0
s = e = 0
while s < len(starts):
if starts[s] < ends[e]:
rooms += 1
max_rooms = max(max_rooms, rooms)
s += 1
else:
rooms -= 1
e += 1
return max_roomsOur AI interviewer asks follow-up questions, challenges your edge cases, and scores your performance. Practice the way real interviews work.
Try a free mock interviewarrow_forwardThe most common categories are arrays/hashing, two pointers, sliding window, trees, and dynamic programming. Problems like Two Sum, Valid Parentheses, Reverse Linked List, and Binary Search appear across almost every company. The 47 examples on this page cover the core patterns you will see at most tech companies.
No. Memorizing solutions fails in interviews because interviewers often modify the problem. Instead, learn the patterns: two pointers for sorted arrays, sliding window for substrings, BFS/DFS for graphs, etc. When you recognize the pattern, you can derive the solution for any variation.
Python is the most popular choice because of its concise syntax and built-in data structures. Java and C++ are also common. Pick whatever language you are fastest in. The interviewer cares about your problem-solving approach, not the language.
For a typical 45-minute interview: spend 5 minutes understanding the problem, 5-10 minutes discussing your approach, 15-20 minutes coding, and 5-10 minutes testing. You should aim to solve medium-difficulty problems in 20-25 minutes of coding time during practice.
Quality matters more than quantity. Solving 75-150 well-chosen problems (like Blind 75 or NeetCode 150) with deep understanding of each pattern is more effective than grinding 500 random problems. Focus on recognizing patterns, not memorizing solutions.