LeetCode Patterns: Top 10 Patterns to Master for Coding Interviews

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.

How to Use This Guide: Study each pattern, understand when to use it, practice the example problems, and then solve similar problems on LeetCode. Focus on pattern recognition rather than memorization.

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)
Key Insight: Two pointers eliminate the need for nested loops, reducing time complexity from O(n²) to O(n).

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
Previous
Next Post »

BOOK OF THE DAY