Most interview problems reduce to a handful of patterns. Recognizing the pattern saves precious interview time.

Pattern 1: Hash Map Lookup

When: Need O(1) lookup, counting, or finding complements.

Classic: Two Sum — find two numbers that add to target.

  def two_sum(nums, target):
    seen = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i
    return []
  

Other problems: Group anagrams, subarray sum equals K, longest consecutive sequence.


Pattern 2: Two Pointers

When: Sorted array, palindrome check, pair finding.

  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 True
  

Other problems: Container with most water, 3Sum, remove duplicates.


Pattern 3: Sliding Window

When: Contiguous subarray/substring with a constraint.

  def max_sum_subarray(nums, k):
    window_sum = sum(nums[:k])
    best = window_sum
    for i in range(k, len(nums)):
        window_sum += nums[i] - nums[i - k]
        best = max(best, window_sum)
    return best

def longest_unique_substring(s):
    seen = {}
    left = best = 0
    for right, char in enumerate(s):
        if char in seen and seen[char] >= left:
            left = seen[char] + 1
        seen[char] = right
        best = max(best, right - left + 1)
    return best
  

When: Sorted data, find boundary, search in rotated array.

  def binary_search(nums, target):
    lo, hi = 0, len(nums) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if nums[mid] == target:
            return mid
        elif nums[mid] < target:
            lo = mid + 1
        else:
            hi = mid - 1
    return -1
  

Variation: Find first/last occurrence, search in 2D matrix.


Pattern 5: BFS / DFS (Graphs & Trees)

BFS — shortest path, level-order:

  from collections import deque

def bfs(graph, start):
    visited = {start}
    queue = deque([start])
    while queue:
        node = queue.popleft()
        for neighbor in graph[node]:
            if neighbor not in visited:
                visited.add(neighbor)
                queue.append(neighbor)

def level_order(root):
    if not root:
        return []
    result, queue = [], deque([root])
    while queue:
        level = []
        for _ in range(len(queue)):
            node = queue.popleft()
            level.append(node.val)
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)
        result.append(level)
    return result
  

DFS — paths, connectivity, backtracking:

  def dfs(graph, node, visited):
    visited.add(node)
    for neighbor in graph[node]:
        if neighbor not in visited:
            dfs(graph, neighbor, visited)

def has_path_dfs(graph, src, dst, visited=None):
    if visited is None:
        visited = set()
    if src == dst:
        return True
    visited.add(src)
    for neighbor in graph[src]:
        if neighbor not in visited and has_path_dfs(graph, neighbor, dst, visited):
            return True
    return False
  

Pattern 6: Dynamic Programming

When: Optimal substructure + overlapping subproblems.

  # Fibonacci — bottom-up
def fib(n):
    if n <= 1:
        return n
    dp = [0, 1]
    for i in range(2, n + 1):
        dp.append(dp[-1] + dp[-2])
    return dp[n]

# Coin change — min coins
def coin_change(coins, amount):
    dp = [float("inf")] * (amount + 1)
    dp[0] = 0
    for a in range(1, amount + 1):
        for coin in coins:
            if coin <= a:
                dp[a] = min(dp[a], dp[a - coin] + 1)
    return dp[amount] if dp[amount] != float("inf") else -1
  

Other problems: Longest increasing subsequence, edit distance, knapsack.


Pattern 7: Stack / Queue

When: Matching brackets, monotonic stack, next greater element.

  def valid_parentheses(s):
    stack = []
    pairs = {")": "(", "]": "[", "}": "{"}
    for char in s:
        if char in "([{":
            stack.append(char)
        elif char in ")]}":
            if not stack or stack[-1] != pairs[char]:
                return False
            stack.pop()
    return len(stack) == 0
  

Complexity Cheat Sheet

Pattern Typical Time Typical Space
Hash map O(n) O(n)
Two pointers O(n) O(1)
Sliding window O(n) O(k)
Binary search O(log n) O(1)
BFS/DFS O(V + E) O(V)
DP O(n × m) O(n) or O(n×m)

Practice

Apply these patterns in Algorithm Exercises. For timed practice, use LeetCode or HackerRank filtered by pattern.

Next: Python Fundamentals Interview Questions