After interviewing at multiple tech companies, these are the questions that came up most often — with clean solutions and explanations.
1. Two Sum
The classic warm-up:
def two_sum(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 []
# Time: O(n), Space: O(n)
assert two_sum([2, 7, 11, 15], 9) == [0, 1]
2. Valid Parentheses
def is_valid(s: str) -> bool:
stack = []
pairs = {')': '(', ']': '[', '}': '{'}
for char in s:
if char in '([{':
stack.append(char)
elif char in pairs:
if not stack or stack[-1] != pairs[char]:
return False
stack.pop()
return len(stack) == 0
assert is_valid("({[]})") == True
assert is_valid("([)]") == False
3. Merge Two Sorted Lists
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def merge_two_lists(l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode()
current = dummy
while l1 and l2:
if l1.val <= l2.val:
current.next = l1
l1 = l1.next
else:
current.next = l2
l2 = l2.next
current = current.next
current.next = l1 or l2
return dummy.next
4. Maximum Subarray (Kadane's Algorithm)
def max_subarray(nums: list[int]) -> int:
max_sum = current_sum = nums[0]
for num in nums[1:]:
current_sum = max(num, current_sum + num)
max_sum = max(max_sum, current_sum)
return max_sum
assert max_subarray([-2, 1, -3, 4, -1, 2, 1, -5, 4]) == 6
5. LRU Cache
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self.cache:
return -1
self.cache.move_to_end(key)
return self.cache[key]
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False)
6. Binary Search
def binary_search(nums: list[int], target: int) -> int:
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 -1
7. Detect Cycle in Linked List
def has_cycle(head: ListNode) -> bool:
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
8. Invert Binary Tree
def invert_tree(root):
if not root:
return None
root.left, root.right = invert_tree(root.right), invert_tree(root.left)
return root
9. Group Anagrams
from collections import defaultdict
def group_anagrams(strs: list[str]) -> list[list[str]]:
groups = defaultdict(list)
for s in strs:
key = tuple(sorted(s))
groups[key].append(s)
return list(groups.values())
assert group_anagrams(["eat","tea","tan","ate","nat","bat"]) == [["eat","tea","ate"],["tan","nat"],["bat"]]
10. Top K Frequent Elements
from collections import Counter
import heapq
def top_k_frequent(nums: list[int], k: int) -> list[int]:
count = Counter(nums)
return heapq.nlargest(k, count.keys(), key=count.get)
assert top_k_frequent([1,1,1,2,2,3], 2) == [1, 2]
Interview Tips
- Always clarify the problem before coding
- Talk through your approach before writing code
- Start with brute force, then optimize
- Test with edge cases: empty input, single element, duplicates
- Know your time and space complexity
- Practice on LeetCode, but understand patterns, not just solutions
The 5 Patterns That Cover 80% of Questions
- Two Pointers / Sliding Window
- Hash Map for O(1) lookups
- BFS/DFS for trees and graphs
- Dynamic Programming (start with recursion + memoization)
- Stack for matching/nesting problems
Key Takeaways
- Most interviews test the same 20-30 patterns
- Hash maps solve an surprising number of problems
- Always consider time AND space complexity
- Communication matters as much as the solution
- Practice explaining your thought process out loud
6. It's okay to start with brute force and optimize
🚀 Level up your AI workflow! Check out my AI Developer Mega Prompt Pack — 80 battle-tested prompts for developers. $9.99
Top comments (0)