LeetCode 8 Patterns
LeetCode 8 Patterns
LeetCode 8 Patterns
Source:
π§ Two Pointers Pattern
πΉ Why Two Pointers Matter
- Optimizes problems involving linear data structures (arrays, strings, linked lists).
- Reduces time complexity from brute-force
O(nΒ²)to efficientO(n). - Useful in situations where youβd otherwise compare every combination of elements.
πΉ Types of Two Pointer Techniques
1. Same Direction
- Pointers move left to right together.
- Ideal for scanning or processing data in a single pass.
- Example: Fast & Slow Pointers
- Detecting cycles in linked lists.
- Finding the middle of a list.
- Slow pointer: moves 1 step.
- Fast pointer: moves 2 steps.
2. Opposite Directions
- One pointer starts at the beginning, the other at the end.
- Common in sorted arrays or for pair-finding tasks.
- Example: Two Sum Problem
- Find two numbers that add to a target.
- Adjust pointers inward based on current sum.
- Efficiently eliminates unnecessary comparisons.
π§ Sliding Window Pattern
πΉ What It Is
- A specialized form of the two pointers technique.
- Focuses on maintaining a dynamic range (window) of elements.
- Used to analyze contiguous subarrays or substrings.
- Adjusts window size dynamically as the data is processed.
πΉ How It Works
- Two pointers define the window: One marks the start, one marks the end.
- Expand: As the end pointer moves forward, the window expands to include more elements.
- Shrink: As conditions are violated or goals are met, the start pointer moves forward to shrink the window.
πΉ Key Use Cases
- Finding maximum/minimum of something in a subarray.
- Tracking running sums, averages, or character counts.
- Searching for longest/shortest substrings meeting certain criteria.
πΉ Example Problem: Longest substring without repeating characters
- Expand the window by moving the end pointer.
- If a duplicate character appears, move the start pointer forward until the duplicate is removed.
- Use a hashmap to track characters inside the window.
π§ Binary Search
πΉ What It Is
- A search algorithm used to find a target in a sorted array.
- Variant of the two pointers technique using a left and right boundary.
- Time complexity:
O(log n)β far more efficient than linear searchO(n).
πΉ How It Works
- Initialize two pointers:
leftat the start,rightat the end. - Find the middle:
mid = (left + right) // 2. - Compare
array[mid]with target:- If equal β return success.
- If
mid < targetβ search the right half. - If
mid > targetβ search the left half.
- Repeat until pointers converge or element is found.
πΉ More Than Just Numbers
Binary Search also works for:
- Monotonic functions: Consistently increasing or decreasing sequences.
- True/False patterns: When a condition changes from false to true in a list (e.g., finding the first
Truein a list of booleans).
πΉ Creative Use Case: Minimum in Rotated Sorted Array
- Even though it seems unsorted, a monotonic condition exists.
- If
element < last elementβ itβs in the rotated section. - If
element > last elementβ itβs in the original sorted section.
π§ Breadth-First Search (BFS)
πΉ What It Is
- Algorithm for exploring graphs or trees level by level.
- Starts from a given node and visits all immediate neighbors before moving to the next level.
πΉ Key Characteristics
- Data Structure: Queue (FIFO - First In, First Out).
- Tracks Visited Nodes: To prevent infinite loops.
- Ideal for: Shortest path in unweighted graphs, Level-order traversal.
πΉ BFS Template Overview
- Initialize a queue and a visited set.
- Add starting node to queue.
- While queue is not empty:
- Remove front node.
- Add to result.
- Add unvisited neighbors to queue.
πΉ Example: Level-Order Traversal
Input Tree: 3 /
9 20 /
15 7
Output: [[3], [9, 20], [15, 7]]
π§ Depth-First Search (DFS)
πΉ What It Is
- Traversal algorithm that explores as far down a branch as possible before backtracking.
- Contrast: BFS goes level-by-level (Queue); DFS dives deep (Stack/Recursion).
πΉ Key Characteristics
- Data Structure: Stack (or call stack via recursion).
- Ideal for: Exploring all paths, cycle detection, backtracking.
πΉ DFS Template (Recursive)
1
2
3
4
5
6
def dfs(node, visited):
if not node or node in visited:
return
visited.add(node)
for neighbor in node.neighbors:
dfs(neighbor, visited)
πΉ Example Problem: Number of Islands
- Goal: Count connected groups of β1βs in a grid.
- Approach: Iterate through grid. If β1β is found, increment count and run DFS to mark all connected β1βs as β0β (visited).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def numIslands(grid): if not grid: return 0 rows, cols = len(grid), len(grid[0]) count = 0 def dfs(r, c): if r < 0 or c < 0 or r >= rows or c >= cols or grid[r][c] == '0': return grid[r][c] = '0' # Mark as visited dfs(r+1, c) dfs(r-1, c) dfs(r, c+1) dfs(r, c-1) for r in range(rows): for c in range(cols): if grid[r][c] == '1': dfs(r, c) count += 1 return count
π Backtracking
πΉ What Is Backtracking?
- Extension of DFS.
- Builds the solution space dynamically.
- Used in combinatorial problems where the full decision tree isnβt known upfront.
πΉ Key Concepts
- Explore options one decision at a time.
- If a dead end or invalid path is reached, backtrack (undo last decision) and try another path.
πΉ Template Pattern
1
2
3
4
5
6
7
8
9
def backtrack(path, options):
if end_condition(path):
result.append(path[:])
return
for option in options:
if is_valid(option):
path.append(option)
backtrack(path, updated_options)
path.pop() # backtrack
πΉ Example: Letter Combinations of Phone Number
Input: β23β -> Output: [βadβ, βaeβ, βafβ, βbdβ, βbeβ, βbfβ, βcdβ, βceβ, βcfβ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def letterCombinations(digits):
if not digits:
return []
digit_map = {
"2": "abc", "3": "def", "4": "ghi", "5": "jkl",
"6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz"
}
result = []
def dfs(index, path):
if index == len(digits):
result.append("".join(path))
return
for char in digit_map[digits[index]]:
path.append(char)
dfs(index + 1, path)
path.pop() # backtrack
dfs(0, [])
return result
- Time Complexity:
O(4βΏ)(Exponential).
β¬οΈ Priority Queue (Heap)
πΉ When to Use
- Top K elements.
- K smallest or K largest values.
πΉ Min vs Max Heap
- Min Heap: Smallest element at root.
- Max Heap: Largest element at root.
πΉ The Counterintuitive Rule
- Find K Smallest β Use Max Heap.
- Why? Keep heap size at K. If a new number is smaller than the largest (root), pop the root and insert the new one.
- Find K Largest β Use Min Heap.
πΉ Efficiency
- Access root:
O(1) - Insert/Remove:
O(log n)
π Dynamic Programming (DP)
πΉ Core Idea
- Break problem into overlapping subproblems.
- Solve each subproblem once and store the result (Memoization).
πΉ Two Main Approaches
1. Top-Down (Memoization)
- Start from main problem, recurse down.
- Store results in dictionary/array.
- Essentially: Backtracking + Caching.
2. Bottom-Up (Tabulation)
- Solve smallest subproblems first.
- Build up to larger problems using loops.
- Often more efficient (no recursion overhead).
πΉ Summary
- DP optimizes exponential brute-force solutions to polynomial time.
- Fundamental for problems involving optimal decisions, counting, and partitioning.
This post is licensed under CC BY 4.0 by the author.