Coding interview patterns every candidate should know
Foundation Patterns: Building Your Interview Toolkit
Foundation Patterns: Building Your Interview Toolkit
Two Pointers: Efficient Array and String Manipulation
The two-pointer technique transforms brute-force nested loops into elegant linear solutions, often reducing O(n²) complexity to O(n). This pattern uses two indices moving through data structures according to specific rules, eliminating redundant comparisons.
Opposite-direction pointers start at array extremes and converge toward the center, making them ideal for palindrome verification and array reversal. One pointer advances from the beginning while another retreats from the end, comparing or swapping elements until they meet.
Same-direction pointers move forward together but at different speeds. The fast-slow pointer approach excels at cycle detection in linked lists—if a cycle exists, the faster pointer eventually catches the slower one, like runners on a circular track.
Sorted arrays unlock powerful two-pointer applications. When searching for pairs that sum to a target, place pointers at opposite ends: if the sum exceeds the target, move the right pointer left; if too small, advance the left pointer. This systematic approach guarantees you'll find valid pairs without examining every combination.
Sliding Window: Mastering Substring and Subarray Problems
The sliding window technique transforms seemingly complex substring and subarray problems into elegant solutions [5]. This pattern specifically targets problems involving contiguous sequences, dividing into two distinct categories.
Fixed window problems maintain a constant size as you traverse the array. When calculating maximum sums or running averages, slide your window one position at a time—subtract the leftmost element, add the new rightmost element. This approach converts an O(n*k) brute force solution into efficient O(n) time [19].
Dynamic windows expand and contract based on conditions. For longest substring challenges, extend the right pointer to grow your window while a condition holds, then shrink from the left when violated. Hash maps become essential here, efficiently tracking character frequencies and element counts within your current window [19].
Pattern recognition is key: whenever problems mention "contiguous," "substring," or "subarray" with specific properties, consider sliding window [14]. This pattern appears frequently in standard coding interviews, making it essential preparation [18].
Fast and Slow Pointers: Detecting Cycles and Finding Midpoints
The Fast & Slow Pointers pattern uses two pointers moving at different speeds to detect cycles in sequences [24]. In a cyclic LinkedList, a fast pointer moving two steps per iteration will eventually meet a slow pointer moving one step per iteration [24]. This approach achieves O(N) time complexity with O(1) constant space [24], making it far more efficient than hash-based solutions.
Floyd's cycle detection works because the fast pointer gains one position per iteration [17]. If a cycle exists, this guarantees convergence—the fast pointer will eventually "lap" the slow pointer within the loop. The technique extends beyond linked lists: Apple frequently tests cycle detection problems [12], while variations handle circular arrays and duplicate detection in constrained spaces.
Finding middle elements becomes trivial with this pattern [17]. When the fast pointer reaches the end, the slow pointer sits at the midpoint—no counting required. This single-pass approach demonstrates how pattern fluency transforms complex problems into elegant solutions.
Advanced Structural Patterns: Trees, Graphs, and Dynamic Programming
Tree Traversal Patterns: DFS, BFS, and Level-Order Processing
Tree traversal patterns form the foundation for solving countless interview problems. Understanding when to apply depth-first search versus breadth-first search transforms seemingly complex challenges into manageable solutions.
Depth-first search explores as far as possible along each branch before backtracking [19]. Implement it recursively for elegant preorder, inorder, and postorder traversals, or iteratively using a stack when recursion depth becomes a concern. Preorder visits nodes before children, inorder processes left subtree, root, then right subtree (crucial for sorted output in BSTs), while postorder handles children before parents.
Breadth-first search uses queues to process nodes level by level, making it ideal for finding shortest paths in trees and handling level-based operations [19]. Both approaches share O(V + E) time complexity, but your choice depends on the problem structure.
Binary Search Tree validation exemplifies pattern recognition [4]. Leverage BST properties—left subtree values less than root, right subtree values greater—to optimize searches and insertions. When validating BSTs, track valid ranges for each subtree rather than simply comparing adjacent nodes.
Graph Search Strategies: Connected Components and Shortest Paths
Graph problems become tractable when you recognize the right traversal strategy. Depth-First Search excels at detecting connected components by marking visited nodes during recursive exploration [19]. DFS can be implemented using either recursion or a stack, making it versatile for cycle detection in directed graphs [19]. For scheduling problems requiring ordered processing, Topological Sort leverages DFS to impose constraints on node sequencing [10].
Breadth-First Search provides the optimal approach for unweighted shortest path problems, exploring neighbors level by level [19]. This Tree Breadth First Search pattern ensures you discover the shortest route before exploring longer alternatives [10].
Union-find data structures offer efficient dynamic connectivity checks, particularly for cycle detection in undirected graphs. This approach outperforms repeated DFS when handling multiple connectivity queries.
Graph representation matters: use adjacency lists for sparse graphs where edges are few relative to vertices. Dense graphs with many connections benefit from adjacency matrices, trading memory for constant-time edge lookups. The Graphs curriculum emphasizes matching data structures to problem constraints [4].
Dynamic Programming Fundamentals: Memoization and Tabulation
Dynamic programming transforms exponential-time problems into polynomial solutions by recognizing two key properties: optimal substructure, where optimal solutions contain optimal subsolutions, and overlapping subproblems, where the same calculations repeat multiple times [4].
Top-down memoization adds caching to recursive solutions. Calculate Fibonacci numbers by storing results in a hash map—when fib(5) needs fib(3), and later fib(4) also needs fib(3), the cached value eliminates redundant recursion. This approach preserves intuitive recursive logic while achieving linear time complexity.
Bottom-up tabulation builds solutions iteratively. Start with base cases in a table, then fill subsequent entries using previously computed values. For the classic coin change problem, iterate through amounts, determining minimum coins needed by checking each denomination [4].
Pattern recognition accelerates problem-solving. The 0/1 knapsack pattern applies when selecting items with constraints. Longest common subsequence emerges in diff tools and DNA analysis. Master these templates, and unfamiliar DP problems become variations of known solutions, reducing interview stress significantly.
Strategic Problem-Solving: Pattern Recognition and Interview Success
Pattern Recognition Framework: Identifying Problem Types Quickly
When confronted with an unfamiliar problem, candidates who use pattern recognition have an 85% success rate [19]. The key lies in analyzing constraints systematically: sorted inputs suggest binary search or two pointers, while optimization keywords like "maximum" or "minimum" often point toward dynamic programming or the 0/1 Knapsack pattern [10].
Developing a mental checklist transforms problem-solving from guesswork into methodical analysis. Tree structures immediately activate breadth-first or depth-first traversal considerations, while "next greater element" phrases signal Monotonic Stack patterns [10]. Creating pattern families from previously solved problems builds this intuition—categorizing each solution by its underlying approach rather than surface details.
Most interview challenges deliberately combine multiple patterns. Finding the shortest path in a weighted graph might require Tree Breadth First Search (BFS) for traversal alongside dynamic programming for optimization [18]. Success requires recognizing these hybrid structures and adapting known patterns to novel contexts, much like students who switch between programming styles perform best [1].
Optimization Strategies: From Brute Force to Efficient Solutions
Optimization begins with clarity. Starting with a brute force solution demonstrates problem understanding before pursuing efficiency [18]. This approach reveals the solution space and establishes correctness as your foundation.
Complexity analysis exposes bottlenecks worth targeting. When nested loops create O(n²) behavior, that's your optimization opportunity. Focus improvements where they matter most—shaving constants from linear operations rarely impresses interviewers [14].
Trading space for time often yields dramatic improvements. Hash maps transform O(n) searches into O(1) lookups, while caching eliminates redundant calculations in recursive solutions [18]. These tradeoffs make sense when memory constraints permit and performance gains justify the cost.
Yet optimization has limits. Understanding theoretical lower bounds prevents futile optimization attempts [14]. Comparison-based sorting cannot beat O(n log n) in the general case. Recognizing these boundaries shows algorithmic maturity—knowing when you've reached optimal complexity matters as much as getting there. The best candidates articulate why further optimization is impossible, not just how they achieved current efficiency.
Communication and Debugging: Demonstrating Professional Readiness
Technical excellence means nothing if you cannot communicate it. Strong candidates verbalize their reasoning continuously, walking interviewers through their problem decomposition before writing code. This transparency reveals systematic thinking—breaking problems into manageable components, considering edge cases, and articulating tradeoffs between approaches [3].
Code quality under pressure separates professionals from amateurs. Even in timed interviews, use descriptive variable names like leftPointer instead of l, structure logic clearly, and add brief comments for complex sections. Clean code demonstrates respect for future maintainers and shows you write production-ready solutions, not just working hacks.
Testing reveals thoroughness. Check empty inputs, single elements, and maximum constraint values systematically. When bugs appear, debug methodically—trace execution step-by-step, verify assumptions explicitly, and explain your reasoning aloud. This collaborative debugging mirrors real engineering work where distributed systems require coordination across teams [23]. Interviewers assess not just whether you find bugs, but how professionally you approach the hunt. Your communication style signals readiness for collaborative software development.

A candidate demonstrates his problem-solving approach during a technical whiteboard interview.
Try InterviewWhisperer on your next interview
A native macOS assistant that hears the question and answers on your screen, invisible to the screen share. Your first 30 minutes of live answers are free, no card.
Requires an Apple Silicon Mac (M1 or later) and macOS 12 or newer.
Practicing first? Try the free interview answer generator. It works on any phone.