LeetCode Patterns: Top 10 Patterns to Master for Coding Interviews
Master these essential problem-solving patterns to crack coding interviews at top tech companies
Introduction
Coding interviews at top tech companies often follow similar patterns. Instead of memorizing solutions, understanding these patterns will help you solve new problems efficiently.
This guide covers the 10 most important LeetCode patterns that appear in 80%+ of coding interviews. Master these patterns, and you'll be able to tackle most interview problems.
Why Patterns Matter
- Most problems are variations of common patterns
- Recognizing patterns saves time during interviews
- Helps you approach problems systematically
- Builds problem-solving intuition
Pattern 1: Two Pointers
Use two pointers moving from different positions to solve problems efficiently, often in O(n) time.
When to Use
- Sorted arrays or linked lists
- Finding pairs that meet a condition
- Reversing or partitioning arrays
- Problems asking for "two elements" or "pair"
Template
int left = 0;
int right = array.length - 1;
while (left < right) {
// Process current pair
if (condition) {
left++;
} else {
right--;
}
}
Example Problems
Problem: Two Sum (Sorted Array)
Find two numbers that add up to target in a sorted array.
vector<int> twoSum(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) {
return {left, right};
} else if (sum < target) {
left++;
} else {
right--;
}
}
return {};
}
// Time: O(n), Space: O(1)
Problem: Remove Duplicates from Sorted Array
Remove duplicates in-place, return new length.
int removeDuplicates(vector<int>& nums) {
if (nums.empty()) return 0;
int write = 0; // Write pointer
for (int read = 1; read < nums.size(); read++) {
if (nums[read] != nums[write]) {
write++;
nums[write] = nums[read];
}
}
return write + 1;
}
// Time: O(n), Space: O(1)
Pattern 2: Sliding Window
Maintain a window of elements and slide it to find optimal subarrays or substrings.
When to Use
- Subarray/substring problems
- Finding longest/shortest subarray with condition
- Problems with "contiguous" or "substring" keywords
- Fixed or variable window size
Template (Variable Window)
int left = 0;
for (int right = 0; right < array.length; right++) {
// Expand window
add(array[right]);
// Shrink window until valid
while (windowInvalid()) {
remove(array[left]);
left++;
}
// Update result
updateResult();
}
Example Problems
Problem: Longest Substring Without Repeating Characters
Find length of longest substring without repeating characters.
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> charMap;
int left = 0;
int maxLen = 0;
for (int right = 0; right < s.length(); right++) {
// If character seen, move left pointer
if (charMap.find(s[right]) != charMap.end()) {
left = max(left, charMap[s[right]] + 1);
}
charMap[s[right]] = right;
maxLen = max(maxLen, right - left + 1);
}
return maxLen;
}
// Time: O(n), Space: O(min(n, m)) where m is charset size
Problem: Maximum Sum Subarray of Size K
Find maximum sum of subarray of fixed size k.
int maxSumSubarray(vector<int>& nums, int k) {
int windowSum = 0;
int maxSum = 0;
// Calculate first window
for (int i = 0; i < k; i++) {
windowSum += nums[i];
}
maxSum = windowSum;
// Slide window
for (int i = k; i < nums.size(); i++) {
windowSum = windowSum - nums[i - k] + nums[i];
maxSum = max(maxSum, windowSum);
}
return maxSum;
}
// Time: O(n), Space: O(1)
Pattern 3: Fast & Slow Pointers
Use two pointers moving at different speeds to detect cycles or find middle elements.
When to Use
- Linked list cycle detection
- Finding middle of linked list
- Finding kth element from end
- Palindrome checking in linked lists
Template
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next; // Move 1 step
fast = fast->next->next; // Move 2 steps
// Process or check condition
}
Example Problems
Problem: Linked List Cycle
Detect if linked list has a cycle.
bool hasCycle(ListNode* head) {
if (head == nullptr) return false;
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
return true; // Cycle detected
}
}
return false;
}
// Time: O(n), Space: O(1)
Problem: Middle of Linked List
Find middle node of linked list.
ListNode* middleNode(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
// Time: O(n), Space: O(1)
Pattern 4: Merge Intervals
Merge overlapping intervals or insert new intervals efficiently.
When to Use
- Overlapping intervals
- Inserting intervals
- Finding conflicting appointments
- Problems with "intervals", "ranges", "schedules"
Template
// Sort intervals by start time
sort(intervals.begin(), intervals.end());
vector<vector<int>> merged;
merged.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++) {
if (intervals[i][0] <= merged.back()[1]) {
// Overlapping - merge
merged.back()[1] = max(merged.back()[1], intervals[i][1]);
} else {
// Non-overlapping - add new
merged.push_back(intervals[i]);
}
}
Example Problems
Problem: Merge Intervals
Merge all overlapping intervals.
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if (intervals.empty()) return {};
// Sort by start time
sort(intervals.begin(), intervals.end());
vector<vector<int>> merged;
merged.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++) {
if (intervals[i][0] <= merged.back()[1]) {
// Overlapping - merge
merged.back()[1] = max(merged.back()[1], intervals[i][1]);
} else {
// Non-overlapping
merged.push_back(intervals[i]);
}
}
return merged;
}
// Time: O(n log n), Space: O(n)
Pattern 5: Cyclic Sort
Sort array in-place when numbers are in range [1, n] or [0, n-1].
When to Use
- Arrays with numbers in range [1, n]
- Finding missing/duplicate numbers
- Problems asking for "first missing positive"
Template
int i = 0;
while (i < nums.size()) {
int correctIndex = nums[i] - 1; // Or nums[i] for 0-based
if (nums[i] != nums[correctIndex]) {
swap(nums[i], nums[correctIndex]);
} else {
i++;
}
}
Example Problems
Problem: Find All Missing Numbers
Find all missing numbers in array [1, n].
vector<int> findDisappearedNumbers(vector<int>& nums) {
int i = 0;
while (i < nums.size()) {
int correctIndex = nums[i] - 1;
if (nums[i] != nums[correctIndex]) {
swap(nums[i], nums[correctIndex]);
} else {
i++;
}
}
vector<int> result;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] != i + 1) {
result.push_back(i + 1);
}
}
return result;
}
// Time: O(n), Space: O(1)
Pattern 6: In-place Reversal
Reverse linked lists or array segments in-place without extra space.
When to Use
- Reversing linked lists
- Reversing array segments
- Problems asking to "reverse" or "rotate"
Template (Linked List)
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr != nullptr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev; // New head
Example Problems
Problem: Reverse Linked List
Reverse a singly linked list.
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr != nullptr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
// Time: O(n), Space: O(1)
Pattern 7: Tree BFS (Breadth-First Search)
Traverse tree level by level using a queue.
When to Use
- Level-order traversal
- Finding level with maximum nodes
- Problems asking for "level" or "depth"
Template
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int levelSize = q.size();
for (int i = 0; i < levelSize; i++) {
TreeNode* node = q.front();
q.pop();
// Process node
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
Example Problems
Problem: Binary Tree Level Order Traversal
Return level-order traversal as nested lists.
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int levelSize = q.size();
vector<int> level;
for (int i = 0; i < levelSize; i++) {
TreeNode* node = q.front();
q.pop();
level.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
result.push_back(level);
}
return result;
}
// Time: O(n), Space: O(n)
Pattern 8: Tree DFS (Depth-First Search)
Traverse tree depth-first using recursion or stack.
When to Use
- Preorder, inorder, postorder traversal
- Path sum problems
- Tree validation
- Finding paths
Template
void dfs(TreeNode* node) {
if (!node) return;
// Preorder: process node first
process(node);
dfs(node->left);
// Inorder: process node here
dfs(node->right);
// Postorder: process node here
}
Example Problems
Problem: Maximum Depth of Binary Tree
Find maximum depth of binary tree.
int maxDepth(TreeNode* root) {
if (!root) return 0;
int leftDepth = maxDepth(root->left);
int rightDepth = maxDepth(root->right);
return 1 + max(leftDepth, rightDepth);
}
// Time: O(n), Space: O(h) where h is height
Pattern 9: Two Heaps
Use min-heap and max-heap to find median or maintain balanced partitions.
When to Use
- Finding median of stream
- Partitioning data into two halves
- Problems asking for "median" or "middle"
Template
priority_queue<int> maxHeap; // Lower half
priority_queue<int, vector<int>, greater<int>> minHeap; // Upper half
void addNum(int num) {
maxHeap.push(num);
minHeap.push(maxHeap.top());
maxHeap.pop();
if (maxHeap.size() < minHeap.size()) {
maxHeap.push(minHeap.top());
minHeap.pop();
}
}
Example Problems
Problem: Find Median from Data Stream
Design data structure to find median of stream.
class MedianFinder {
priority_queue<int> maxHeap; // Lower half
priority_queue<int, vector<int>, greater<int>> minHeap; // Upper half
public:
void addNum(int num) {
maxHeap.push(num);
minHeap.push(maxHeap.top());
maxHeap.pop();
if (maxHeap.size() < minHeap.size()) {
maxHeap.push(minHeap.top());
minHeap.pop();
}
}
double findMedian() {
if (maxHeap.size() > minHeap.size()) {
return maxHeap.top();
}
return (maxHeap.top() + minHeap.top()) / 2.0;
}
};
// Time: O(log n) per operation, Space: O(n)
Pattern 10: Subsets
Generate all subsets or combinations using backtracking.
When to Use
- Generating all subsets
- Combination problems
- Permutation problems
- Problems asking for "all possible"
Template
void backtrack(vector<int>& nums, int start, vector<int>& current,
vector<vector<int>>& result) {
result.push_back(current); // Add current subset
for (int i = start; i < nums.size(); i++) {
current.push_back(nums[i]); // Choose
backtrack(nums, i + 1, current, result); // Explore
current.pop_back(); // Unchoose
}
}
Example Problems
Problem: Subsets
Generate all subsets of array.
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> result;
vector<int> current;
backtrack(nums, 0, current, result);
return result;
}
void backtrack(vector<int>& nums, int start, vector<int>& current,
vector<vector<int>>& result) {
result.push_back(current);
for (int i = start; i < nums.size(); i++) {
current.push_back(nums[i]);
backtrack(nums, i + 1, current, result);
current.pop_back();
}
}
// Time: O(2^n), Space: O(n)
Practice Problems by Pattern
Two Pointers
- Two Sum (sorted)
- 3Sum
- Container With Most Water
- Trapping Rain Water
Sliding Window
- Longest Substring Without Repeating Characters
- Minimum Window Substring
- Longest Repeating Character Replacement
- Maximum Sum Subarray of Size K
Fast & Slow Pointers
- Linked List Cycle
- Middle of Linked List
- Palindrome Linked List
- Remove Nth Node From End
Merge Intervals
- Merge Intervals
- Insert Interval
- Non-overlapping Intervals
- Meeting Rooms
Cyclic Sort
- Find All Missing Numbers
- Find Duplicate Number
- First Missing Positive
Study Strategy
- Week 1-2: Study patterns 1-5, solve 3-5 problems per pattern
- Week 3-4: Study patterns 6-10, solve 3-5 problems per pattern
- Week 5-6: Mixed practice, focus on weak patterns
- Week 7-8: Mock interviews, timed practice
Interview Tips
- Identify the pattern first before coding
- Explain which pattern you're using and why
- Start with brute force, then optimize
- Practice drawing diagrams for complex problems
- Time yourself to improve speed
Sign up here with your email
ConversionConversion EmoticonEmoticon