When I was interviewing for roles at Microsoft and Facebook, I — like many developers — spent as many hours as I could crunching through numerous coding problems. This was brutally exhausting. I felt like I was stuck in a loop, solving problem after problem, but not actually gaining confidence.
Looking back, the problem with this approach is clear: for efficient coding interview prep, we should learning coding patterns instead of grinding individual problems.
Here’s why coding patterns are so powerful: Most coding interview questions boil down to a handful of key patterns. Once you understand the logic behind a pattern, you can apply it to dozens of problems. This not only saves you time — it prepares you for the unknown.
Today, I’ll share 5 key patterns you should learn for coding interview success:
Let’s get started.
Why curated problem lists are efficient
With seemingly endless pools of practice problems out there, many coding interview prep platforms offer curated lists that feature the most common coding interview problems. These lists are tailored to save you time and help you focus on mastering the problems that matter.
Some of the most popular problem lists include:
- Blind75
- Grind75
- LeetCode75
- Neetcode150
- Educative77
But what do these lists have in common?
They all emphasize some common coding problems that correspond to certain coding patterns.
Here are the common interview problems represented across these problem lists and the patterns underlying them:
Problem Title | Coding Pattern |
---|---|
Valid Palindrome | Two Pointers |
Kth Smallest Number in M Sorted Lists | k-Way Merge |
Serialize and Deserialize Binary Tree | Tree Depth-First Search |
Valid Anagram | Knowing What to Track |
Minimum Window Substring | Sliding Window |
This overlap in problem represent how common these problems and their patterns are. This is exactly why I’m introducing you to these 5 key patterns now.
But first, here’s 2 things you should know:
- Learning these 5 patterns will help you solve 40+ problems: They won’t just help you unlock these 5 problems above. Their application across many problems is the core of what makes patterns powerful.
- There are many more coding patterns to learn: These patterns alone will not be enough to be fully prepared for your interview, but they’re a great starting point.
Let’s move on to these patterns and their applications to specific problems.
5 key coding patterns to learn
1. Two Pointers
The Two Pointers coding pattern maintains two pointers that traverse the data structure in a coordinated manner, typically starting from different positions or moving in opposite directions. By dynamically adjusting based on specific conditions or criteria, this pattern enables solutions with optimal time and space complexity. For example, to identify whether a string is a palindrome, we can use one pointer to iterate from the beginning and another from the end, comparing values at each step.
Consider the following template code where the two pointers left
and right
are adjusted while the conditions for a specific given problem are compared:
Template code for Two Pointers pattern
Let’s solve an interview problem to see the Two Pointers coding pattern in action.
Solving the Valid Palindrome problem with Two Pointers
To solve the Valid Palindrome problem using the Two Pointers pattern, we utilize two pointers—one starting from the beginning of the string and the other from the end. We traverse the string simultaneously, comparing characters at corresponding positions. By advancing the pointers toward each other while checking for equality, we efficiently determine if the string is a palindrome.
Valid Palindrome
2. k-Way Merge Pattern
If you have k input lists that are sorted, and you need to merge them into a single sorted list, what’s your game plan? The k–Way Merge coding pattern is your go-to strategy for solving this challenge. The k-Way merge pattern merges k sorted data structures into a single sorted one, expanding on the merge sort algorithm. Here’s how it works:
- Use a min-heap: Begin by inserting the first element of each list into a min-heap. This helps track the smallest current element among the lists.
- Remove and add: Continuously remove the smallest element from the heap (at the top) and add it to the output list, maintaining the sorted order.
- Track and insert: Track the origin of each element in the heap, ensuring that after adding an element to the output list, the subsequent element from its corresponding list is inserted into the heap.
- Repeat until done: Continue steps 2–3 until all elements from all input lists are merged into the output list. This systematic approach ensures a final output list in sorted order.
Consider the following self-explanatory template code for the k-way merge pattern:
Template code for K-way Merge pattern
Let’s put the k-way Merge coding pattern into action with an example problem.
Solving the k-th Smallest Number in M Sorted Lists problem with k-Way Merge
This algorithm inserts the first element of each list into the min-heap, which ensures that the element with the smallest value is always at the top. As it progresses, the algorithm continuously extracts the smallest element from the heap. If this element has a successor in its original list, that successor is then inserted back into the min-heap. This process repeats until the k-th smallest element is found or until all elements are processed.
Kth Smallest Number in M Sorted Lists
3. Tree Depth-First Search
The Tree Depth-First Search (DFS) pattern involves traversing a binary tree by exploring as far down one branch as possible before backtracking and exploring other branches. DFS can be implemented in three main ways:
- Preorder traversal: Visit the root node first, then recursively traverse the left subtree followed by the right subtree.
- In-order traversal: Traverse the left subtree first, visit the root node, and then traverse the right subtree, which is useful for binary search trees to retrieve elements in ascending order.
- Postorder traversal: Traverse the left subtree, then the right subtree, and visit the root node last.
DFS can be implemented using either recursion or an explicit stack.
- In the recursive approach, a helper function is used to visit nodes, processing the current node and then recursively traversing its child nodes. This recursive method leverages the call stack to manage the traversal state, making it intuitive and straightforward to implement.
- In the stack-based approach, we initialize a stack with the root node, then repeatedly pop a node from the stack, process it, and push its child nodes onto the stack. This method mimics the recursive approach but uses a manual stack to keep track of nodes.
The following is the template code for the recursive method-based implementation of in-order, pre-order, and post-order DFS traversal:
Template code for Tree Depth First Search pattern – Pre-order traversal
Template code for Tree Depth First Search pattern – In-order traversal
Template code for Tree Depth First Search pattern – Post-order traversal
Let’s apply the Tree Depth-First Search coding pattern with a specific interview problem now.
Solving the Serialize and Deserialize Binary Tree problem with Tree Depth-First Search
Serialization captures the binary tree structure by traversing it in a pre-order manner and representing each node’s value, or NULL otherwise, using a compact stream format. Deserialization reconstructs the binary tree from the serialized stream, recursively creating nodes and their subtrees based on the preorder traversal order and interpreting markers to reconstruct the original tree structure.
Here’s a more detailed breakdown of the algorithm for serializing and deserializing a binary tree using DFS:
Serialization:
- Depth-first traversal: Start traversing the binary tree from the root node.
- Pre-order serialization: Serialize each node encountered in a preorder manner, meaning first serialize the current node (root), then its left subtree, and finally its right subtree.
- Appending nodes: As each node is visited during traversal, append its value to the stream.
- Marker for NULL pointers: Whenever encountering a NULL node (leaf node or child of a leaf node), serialize a marker (e.g., “M”) to represent the absence of a child node.
- Stream representation: Serialize the binary tree into a stream of values and markers, representing the structure of the tree in a compact format.
Deserialization:
- Pre-order traversal: Begin deserialization by traversing the serialized stream in a preorder manner.
- Node creation: For each value encountered in the stream:
- If the value is a marker, it represents a NULL node. Do not create a node for NULL pointers.
- If the value is not a marker, create a new node with the value and continue deserialization.
- If the value is a marker, it represents a NULL node. Do not create a node for NULL pointers.
- Recursive construction: As nodes are created, recursively construct the left and right subtrees of each non-NULL node using the preorder traversal order.
- Handling markers: When encountering markers in the stream, interpret them as NULL nodes, and do not create corresponding child nodes.
Serialize and Deserialize Binary Tree
main
Binary Tree
Tree Node
4. Knowing What to Track
The Knowing What to Track pattern involves efficiently solving problems by counting the occurrences of elements or tracking other parameters in a given data structure and utilizing this information to derive solutions. It consists of two main phases:
Tracking phase:
- Iterate and count: Traverse through the elements of the data structure and count the frequency or other parameters of each element.
- Data structures: Utilize various data structures such as hash maps, dictionaries, arrays, or simple variables to store and update tracking information.
Utilization phase:
- Problem-solving: Use the information obtained during the tracking phase to solve specific problems efficiently.
- Examples: Solutions can involve tasks like finding the most frequent element, identifying elements occurring only once, checking for permutations, or determining game outcomes.
Consider the following template code for both phases of the pattern:
Template code for Knowing What to Track pattern
Let’s now solve an interview problem to better understand the Knowing What to Track coding pattern.
Solving the Valid Anagram problem with Knowing What to Track
The algorithm iterates over each character in str1
, updating the count in a hash map. Then, it decrements counts for characters in str2
. If any count becomes non-zero, it concludes that str2
cannot be an anagram of str1
, returning FALSE. Conversely, if all counts are zero, it determines that the occurrences of each character in both strings are identical, returning TRUE.
Valid Anagram
5. Sliding Window
The Sliding Window pattern employs two pointers to create a dynamic window that traverses through sequential data, such as arrays or strings. As this window moves forward, it computes calculations only on the newly added elements, updating previous computations by removing existing elements. By focusing on relevant subsets of data and avoiding redundant calculations, this approach efficiently solves problems involving contiguous data processing.
Consider the following self-explanatory code template for the Sliding Window pattern:
Template code for the Sliding Window pattern
Let’s put Sliding Window coding pattern to the test with a coding problem now.
Solving the Minimum Window Substring problem with Sliding Window
The algorithm uses two hash maps:
- One to store the frequency of each character in the second string (
req_count
) - Another to track these characters within the current window in the first string (
window_hashmap
).
Two pointers (left and right) define the sliding window over the first string. The right pointer expands the window by moving through the first string, and during this process, it updates the character count in the window_hashmap
hash map.
When a character’s frequency in the window matches its frequency in the second string (req_count
), a counter (current
) is incremented. This is checked by comparing the frequency of the character in the current window (tracked by the window_hashmap
) with its required frequency as per the second string (req_count
). When these frequencies match, it indicates that the current window contains the required number of occurrences of that character from the second string. Therefore, the current
counter is incremented to keep track of how many characters in the current window meet their required frequencies from the second string.
Once the window contains all characters of the second string, the left pointer is moved to shrink the window and find the smallest valid substring. The window’s counts are updated, and its validity is checked after each move. The smallest valid window found is updated if the current window is smaller. After the right pointer has traversed the first string, the smallest valid window is returned, or an empty string if no valid window exists. This approach ensures optimal processing time.
Minimum Window Substring
Focus on patterns — not problems
There are countless coding problems out there, but the truth is, most interviews focus on a few key patterns. If you understand these patterns and know how to apply them, you’ll be able to handle a wide variety of problems without hesitation or stress.
As mentioned earlier, Educative-77 is one of the curated problem lists that’s excellent for efficient interview prep. With it, you can prepare for the unknown in a crunch by mastering 26 coding patterns that apply to thousands of problems across top tech companies.
Educative-77 in Python: Accelerate Your Coding Interview Prep: Why solve 2800 problems when you can master 26 problem-solving patterns to crack any coding interview? Each module presents a set of related coding patterns, and is available in JavaScript, C++, Java, and Go, with more coming soon!
If you have more time, I’d recommend going deeper with your interview prep. To that end, you may find Educative’s Coding Interview Patterns Course series, where you can apply those 26 patterns to even more practice problems in an AI-powered, hands-on platform.
Happy learning — and good luck prepping!