Cracking coding interview: 5 key patterns to learn

Top interview questions and answers

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: 

  • Valid Palindrome
  • Kth Smallest Number in M Sorted Lists
  • Serialize and Deserialize Binary Tree
  • Valid Anagram
  • Minimum Window Substring

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:

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:

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:

  1. 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.
  2. 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 kWay 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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:

  1. Depth-first traversal: Start traversing the binary tree from the root node.
  2. 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.
  3. Appending nodes: As each node is visited during traversal, append its value to the stream.
  4. 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.
  5. Stream representation: Serialize the binary tree into a stream of values and markers, representing the structure of the tree in a compact format.

Deserialization:

  1. Pre-order traversal: Begin deserialization by traversing the serialized stream in a preorder manner.
  2. 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.
  3. Recursive construction: As nodes are created, recursively construct the left and right subtrees of each non-NULL node using the preorder traversal order.
  4. 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

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!

Frequently Asked Questions

How can learning overlapping coding patterns help in interview preparation?

Learning these patterns allows you to tackle problems with similar approaches, reducing the need to memorize individual solutions and boosting your ability to solve problems quickly.

How do I practice recognizing coding patterns?

You can practice by solving problems on platforms like LeetCode, Educative, and GeeksforGeeks, focusing on grouping problems by patterns and understanding how to apply them in different contexts.

Do I need to learn all coding patterns for interviews?

While covering every problem is impossible, focusing on key coding patterns that overlap across multiple problem types will help you solve most interview questions.

Are there any specific resources to learn coding patterns?

Yes, resources like Grokking the Coding Interview Patterns by Educative and LeetCode’s curated problem lists are great places to start learning and practicing these patterns.

What’s the best way to approach problems that don’t clearly match a known pattern?

When you encounter problems that don’t fit a specific pattern, break them down into smaller components, look for similarities to problems you’ve solved before, and consider if a combination of patterns could be applied.