Coding Interview
Examples
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.
How coding interviews actually work
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 10 patterns that cover 90% of interviews
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
Two Pointers
Sliding Window
Stack
Binary Search
Linked List
Trees
Dynamic Programming
Graphs
Intervals & Greedy
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
Arrays & Hashing
Two Sum
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
- 1Create a hash map to store each number and its index
- 2For each number, check if (target - num) exists in the map
- 3If found, return both indices. Otherwise, add the current number to the map
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] = iContains Duplicate
Given an integer array, return true if any value appears at least twice.
Input: nums = [1,2,3,1] Output: true
Approach
- 1Add each element to a set
- 2Before adding, check if it already exists in the set
- 3If it does, we found a duplicate
def contains_duplicate(nums):
seen = set()
for num in nums:
if num in seen:
return True
seen.add(num)
return FalseValid Anagram
Given two strings s and t, return true if t is an anagram of s.
Input: s = "anagram", t = "nagaram" Output: true
Approach
- 1Count character frequencies in both strings
- 2Compare the two frequency maps
- 3If all counts match, it is an anagram
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 TrueGroup Anagrams
Given an array of strings, group the anagrams together.
Input: ["eat","tea","tan","ate","nat","bat"] Output: [["eat","tea","ate"],["tan","nat"],["bat"]]
Approach
- 1Sort each string to create a canonical key
- 2Use a hash map with the sorted key
- 3Group strings that share the same sorted key
def group_anagrams(strs):
groups = {}
for s in strs:
key = tuple(sorted(s))
groups.setdefault(key, []).append(s)
return list(groups.values())Top K Frequent Elements
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
- 1Count frequencies with a hash map
- 2Use bucket sort: index = frequency, value = list of nums
- 3Walk buckets from highest to lowest, collect k elements
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 resultProduct of Array Except Self
Return 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
- 1Build a prefix product array (left to right)
- 2Build a suffix product array (right to left)
- 3Multiply prefix[i] * suffix[i] for the answer
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 resultLongest Consecutive Sequence
Given 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
- 1Put all numbers in a set for O(1) lookup
- 2For each number, check if (num - 1) is NOT in the set (start of a sequence)
- 3If it is a start, count consecutive numbers upward
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 longestTwo Pointers
Valid Palindrome
Given 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
- 1Use two pointers: one at the start, one at the end
- 2Skip non-alphanumeric characters
- 3Compare characters moving inward
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 TrueTwo Sum II (Sorted Array)
Given 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
- 1Use two pointers at the start and end
- 2If sum is too large, move the right pointer left
- 3If sum is too small, move the left pointer right
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 -= 13Sum
Find 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
- 1Sort the array first
- 2Fix one number, then use two pointers for the remaining pair
- 3Skip duplicates at each level to avoid repeated triplets
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 resultContainer With Most Water
Given 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
- 1Start with two pointers at both ends (widest container)
- 2Calculate area = min(height[l], height[r]) * (r - l)
- 3Move the pointer pointing to the shorter line inward
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 bestTrapping Rain Water
Given 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
- 1Use two pointers from both ends
- 2Track the max height seen from the left and right
- 3Water at each position = min(leftMax, rightMax) - height[i]
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 waterSliding Window
Best Time to Buy and Sell Stock
Given 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
- 1Track the minimum price seen so far
- 2At each step, calculate profit = current - min_price
- 3Keep the maximum profit found
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_profitLongest Substring Without Repeating Characters
Find the length of the longest substring without repeating characters.
Input: s = "abcabcbb"
Output: 3 ("abc")Approach
- 1Use a sliding window with a set to track characters
- 2Expand the right pointer and add characters
- 3If a duplicate is found, shrink from the left until it is removed
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 resultLongest Repeating Character Replacement
Given 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
- 1Sliding window tracking character frequencies
- 2Window is valid if: window_size - max_freq <= k
- 3If invalid, shrink from the left
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 resultMinimum Window Substring
Given strings s and t, find the minimum window in s that contains all characters of t.
Input: s = "ADOBECODEBANC", t = "ABC" Output: "BANC"
Approach
- 1Count required characters from t
- 2Expand window right, tracking how many required chars are satisfied
- 3Once all satisfied, shrink from left to find the minimum
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]Stack
Valid Parentheses
Given a string containing just '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
Input: s = "()[]{}"
Output: trueApproach
- 1Push opening brackets onto a stack
- 2For closing brackets, check if the top of the stack matches
- 3At the end, the stack should be empty
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) == 0Min Stack
Design 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
- 1Use two stacks: one for values, one for tracking the current minimum
- 2On push, also push to min_stack if the value is <= current min
- 3On pop, also pop from min_stack if the value equals current min
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 Reverse Polish Notation
Evaluate an arithmetic expression in Reverse Polish Notation (postfix).
Input: tokens = ["2","1","+","3","*"] Output: 9 ((2+1)*3)
Approach
- 1Use a stack to hold operands
- 2When you see a number, push it
- 3When you see an operator, pop two operands, apply the operator, push the result
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]Daily Temperatures
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
- 1Use a monotonic decreasing stack of indices
- 2For each temperature, pop indices where current temp is warmer
- 3The difference in indices is the number of days to wait
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 resultBinary Search
Binary Search
Given 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
- 1Set left and right pointers to the start and end
- 2Calculate mid, compare with target
- 3Narrow the search space by half each iteration
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 a 2D Matrix
Search 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
- 1Treat the 2D matrix as a flat sorted array
- 2Use binary search with index conversion: row = mid // cols, col = mid % cols
- 3Standard binary search on the virtual 1D array
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 Eating Bananas
Koko 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
- 1Binary search on the answer (speed k)
- 2For each candidate speed, calculate total hours needed
- 3Find the minimum speed where total hours <= h
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 in Rotated Sorted Array
Search 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
- 1Use binary search, identify which half is sorted
- 2Check if target falls within the sorted half
- 3Narrow search to the correct half
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 -1Linked List
Reverse Linked List
Reverse a singly linked list.
Input: 1 -> 2 -> 3 -> 4 -> 5 Output: 5 -> 4 -> 3 -> 2 -> 1
Approach
- 1Use three pointers: prev, curr, next_node
- 2At each step, reverse the .next pointer
- 3Move all three pointers forward until curr is None
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 Lists
Merge two sorted linked lists into one sorted list.
Input: 1->2->4, 1->3->4 Output: 1->1->2->3->4->4
Approach
- 1Create a dummy node as the head of the merged list
- 2Compare current nodes of both lists, attach the smaller one
- 3When one list is exhausted, attach the remainder of the other
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.nextLinked List Cycle
Determine if a linked list has a cycle.
Input: 3 -> 2 -> 0 -> -4 -> (back to 2) Output: true
Approach
- 1Use Floyd's cycle detection: slow pointer (1 step) and fast pointer (2 steps)
- 2If they meet, there is a cycle
- 3If fast reaches None, there is no cycle
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 Nth Node From End
Remove 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
- 1Use two pointers with an n-gap between them
- 2Move the fast pointer n steps ahead first
- 3Then move both until fast reaches the end; slow is at the target
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 List
Reorder 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
- 1Find the middle using slow/fast pointers
- 2Reverse the second half of the list
- 3Merge the two halves by alternating nodes
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, tmp2Trees
Invert Binary Tree
Invert a binary tree (mirror it).
Input: 4 Output: 4
/ \ / \
2 7 7 2
/ \ / \ / \ / \
1 3 6 9 9 6 3 1Approach
- 1Recursively swap the left and right children of every node
- 2Base case: if node is None, return None
- 3Swap, then recurse on both children
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 rootMaximum Depth of Binary Tree
Find 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
- 1Recursively compute the depth of left and right subtrees
- 2The depth of the current node = 1 + max(left_depth, right_depth)
- 3Base case: empty node has depth 0
def max_depth(root):
if not root:
return 0
return 1 + max(max_depth(root.left), max_depth(root.right))Same Tree
Check if two binary trees are structurally identical with the same values.
Input: p = [1,2,3], q = [1,2,3] Output: true
Approach
- 1If both nodes are None, they match
- 2If one is None or values differ, they don't match
- 3Recursively check left and right subtrees
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)Subtree of Another Tree
Check if tree t is a subtree of tree s.
Input: s = [3,4,5,1,2], t = [4,1,2] Output: true
Approach
- 1At each node of s, check if the subtree rooted there matches t
- 2Use the same_tree function as a helper
- 3Recurse through all nodes of s
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)Lowest Common Ancestor of BST
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
- 1Use the BST property: left < root < right
- 2If both nodes are smaller, go left. If both are larger, go right
- 3Otherwise, the current node is the LCA
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 rootValidate Binary Search Tree
Determine 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
- 1Pass a valid range (min, max) down the tree
- 2For each node, check if its value is within the allowed range
- 3Update the range as you recurse: left gets upper bound, right gets lower bound
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))Dynamic Programming
Climbing Stairs
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
- 1This is the Fibonacci sequence: ways(n) = ways(n-1) + ways(n-2)
- 2Base cases: ways(1) = 1, ways(2) = 2
- 3Build up from the bottom using two variables
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 bHouse Robber
Rob 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
- 1At each house, choose: rob it + best from 2 houses back, or skip it
- 2dp[i] = max(dp[i-1], dp[i-2] + nums[i])
- 3Only need two previous values, not a full array
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 prev1Coin Change
Given 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
- 1Build a DP array where dp[i] = min coins to make amount i
- 2For each amount, try every coin denomination
- 3dp[amount] = min(dp[amount], dp[amount - coin] + 1)
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 -1Longest Increasing Subsequence
Find 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
- 1Maintain a list 'tails' where tails[i] is the smallest tail of all increasing subsequences of length i+1
- 2For each number, binary search for its position in tails
- 3Either extend the longest subsequence or replace an existing tail
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)Word Break
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
- 1dp[i] = true if s[0:i] can be segmented
- 2For each position i, check all possible last words
- 3dp[i] = true if dp[j] is true and s[j:i] is in the dictionary
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)]Maximum Subarray
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
- 1Kadane's algorithm: track current sum and max sum
- 2At each element, decide: start fresh or extend the current subarray
- 3current_sum = max(num, current_sum + num)
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_sumGraphs
Number of Islands
Given 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
- 1Scan the grid for unvisited land cells
- 2When found, increment count and BFS/DFS to mark all connected land
- 3Repeat until all cells are visited
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)Clone Graph
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
- 1Use a hash map to track original -> clone mapping
- 2BFS or DFS through the graph
- 3For each node, create its clone and recursively clone neighbors
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)Course Schedule
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
- 1Build an adjacency list from prerequisites
- 2Use topological sort (BFS with in-degree tracking)
- 3If all courses are processed, there is no cycle
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_coursesIntervals & Greedy
Merge Intervals
Given 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
- 1Sort intervals by start time
- 2Iterate and merge if current overlaps with the last merged interval
- 3Two intervals overlap if current.start <= last.end
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 mergedNon-overlapping Intervals
Find 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
- 1Sort by end time (greedy: keep intervals that end earliest)
- 2Track the end of the last kept interval
- 3If current starts before last end, it overlaps and must be removed
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 countMeeting Rooms II
Given meeting time intervals, find the minimum number of conference rooms required.
Input: [[0,30],[5,10],[15,20]] Output: 2
Approach
- 1Separate start and end times, sort each
- 2Use two pointers to sweep through events
- 3When a meeting starts before one ends, we need another room
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_roomsReading solutions is step one.
Solving them under pressure is step two.
Our 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_forwardFrequently Asked Questions
What coding problems are most commonly asked in interviews?add
The 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.
Should I memorize coding interview solutions?add
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.
What programming language should I use in coding interviews?add
Python is the most popular choice because of its concise syntax and built-in data structures. Java and C++ are also common. If you are interviewing for a Java role, see our Java interview questions guide for 1,715 questions ranked by frequency. Pick whatever language you are fastest in. The interviewer cares about your problem-solving approach, not the language.
How long should it take to solve a coding interview problem?add
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.
How many problems should I practice before interviews?add
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.